对象代龄

  代龄是旨在提高垃圾收集器性能的一种机制。有以下几点:

  1. 对象越新,其生存期越短;
  2. 对象越老,其生存期越长;
  3. 对托管堆的一部分执行垃圾收集要比对整个托管堆执行垃圾收集速度要快。

  在托管堆初始化时,其中不包含任何对象。这时添加到托管堆中的对象被称为第0代对象。第0代对象就是新构造的对象,垃圾收集器还没有对他们执行过任何的检查,加入新启动一个应用程序托管堆,分配了5个对象(A到E),经过一段时间后,对象C和E将变为不可达对象。

  当CLR初始化时,它会为第0代对象选择一个阈值,假定为256KB。(实际可能会与此不同)当分配新对象导致第0代对象超过了为其设定的阙值时,垃圾收集器就必须启动了。假定上面的A到E总共占用了256KB,那么当F开始被分配时,垃圾收集器就会启。垃圾收集器判定对象C和E为垃圾,因此会压缩对象D使其邻接于对象B。此次垃圾收集器中存活下来的对象(对象A,B,D)将被认为是第1代对象。经过一轮垃圾收集的检查加强的存活下来并且光荣的升官加爵。

  在第一次垃圾收集执行后,0代对象暂时空缺。但很快,随着应用程序的运行,又有新的对象被分配而成为第0代对象。新加入的F到K就变为了0代对象变为了准炮灰。随着应用程序的运行,对象B(一代长老),H(0)和J(0)又成为不可达对象,它们的内存也要在某一点被回收。

  现在假设应用程序又试图分配对象L,这将在一次使第0代对象超过它的阙值容量,于是又必须开始执行第二次垃圾收集。在这前面,垃圾收集器必须要判定要收集那些代的对象。垃圾收集器期会为0代对象选择一个阙值(大约256KB),其实也会为第1代对象选择一个阙值容量。假设第1代对象的阙值容量为2MB。

  当第二次垃圾收开始执行时,它也会查看第1代对象占用了多少内存,在本例中,由于第一代对象(A,B,D)占用内存远少于2MB,所以垃圾收集器只会去检查第0代对象。由于新创建的对象的生存期比较短,所以第0代对象成为垃圾对象的数量会比较多,因此对第0代对象执行垃圾收集将有可能比较多的内存,忽略掉第1代对象提高垃圾收集的速度。

  忽略第1代对象的意义不仅仅在于不对它们执行垃圾收集。实际上,更重要的是垃圾收集器不用再遍历整个托管堆中的对象了,可以提高垃圾收集器的性能。说忽略代龄较大的对象的一些内部引用,而不是全部内部引用是因为代龄较大的对象有可能引用一个新的对象。为了确保这些代龄较大的对象中的一些新对象也能被检测到,垃圾收集器使用JIT编译器内部的一种机制来在对象的内部引用字段改变时设置一个相应的为标记。这使得垃圾收集器可以知道自从上次垃圾收集执行后以来,那些代龄较大的对象已经被应用程序所改写。这样垃圾收集器只需检查它们是否引用了第0代对象就可以了。

  生存期比较长的对象将趋向于继续存活,所以第一代对象继续成为可达对象的可能性比较大。所以第一代对象继续成为可达对象的可能性比较大。因此垃圾收集器检查第一代对象,很有可能找不到很多垃圾,能够回收的内存也就有限,这样收集第一代很有可能浪费大量的时间。如果垃圾对象位于第一代,那么它仍然健在。第二次垃圾收集后。托管堆中存在

  A--B---D---F--G---I---K(均为一代长老了)

  第0代对象中的幸存者有升官加爵了变为1代,因为垃圾收集器没有检查第一代,B内存没有被收集。虽然已经成为不可达对象。但是由于没有经历洗礼,所以没有升官加爵;

  此时0代为空,新的对象继续加入成为了0代长老(L到O),过一段时间,G、L、M又成为不可达对象。此时托管堆如下:

  一代A---B---D---F---G---I---K 0代L---M---N---O

  此时1代中堆着N多的不可达垃圾包括B。

  此时对象P的加入又是0代超标了,继续垃圾收集。因为1代的容量2MB,没有超标,继续不对1代收集(B,G为1代中的蛀虫);本次垃圾收集完毕后,托管堆如下:

  一代A---B---D---F---G---I---K---N----O

  0代被适时杀死,一代里面的蛀虫继续增长,没有控制是不行的,结果一代的容量达到了其阙值2MB,此时应用程序分配P到S对象,这时0代又满了。此时托管堆的分配情况:

  一代A---B---D---F---G---I---K---N----O  0代P----Q----R----S

  此时应用程序试图分配对象T,当然是没有地方了,0,1代都满了,需要清理了,这时发现一代对象的内存容量已经达到了2MB,然而一代中存在着大量幸存下来的垃圾。本次垃圾收集器是公平的,同时收集第0代和第1代中所有的垃圾对象,痛苦,所以的垃圾一扫而光了,此时托管堆为:

  二代D---F---I----N----O  二代Q-----S(0代空了)

  和前面一样,本次垃圾收集完毕后,幸存下来的将被提升为1代,而一代中存活下来的被荣升为2代了,0代为空了,在产生第二代对象之前,系统有可能已经执行了多次垃圾收集,但只有在第一代对象的内存总量达到其阙值时,垃圾收集器才会检查一代对象,而此时系统可能已经对0代对象执行了N多次垃圾收集了。

  CLR托管堆只支持3个代龄,0,1,2,CLR初始化时都会为其设置阙值容量(大约为,256KB,2MB,10MB),

  CLR垃圾收集器是一个自调结的玩意,他会根据对象的状态,变为不可达的频率自适应的调节阙值。实在是高啊。

  CLR的垃圾收集原理其实也给人一人生道理,要想活得更长,就需向更高一层走,而要想往更高一层走就要经过残酷的洗礼。剩者为王。

 

  • 屠刀总是先指向弱者,因为强者数大根深啊,杀一次得不偿失
  • 强者拥有更多的资源和更多的容忍
  • 再强也不要超过别人给的限度,否则权利是人家给的,人家不高兴了随时可以拿回去

【转】.net框架读书笔记---CLR内存管理\垃圾收集(六)相关推荐

  1. 【转】.net框架读书笔记---CLR内存管理\垃圾收集(四)

    弱引用 当一个根指向一个对象时,该对象不可能被垃圾收集器收集,在这种情况下,通常说存在一个该对象的强引用(strong reference).垃圾收集器还支持弱引用(weak reference)的概 ...

  2. 【转】.net框架读书笔记---CLR内存管理\垃圾收集(三)

    接上一篇.net框架读书笔记---CLR内存管理\垃圾收集(二),主要学习了终止化对象(实现了Finalize方法的对象),了解了终止化对象的弊端,学习了通过实现IDisposable接口,通过Dis ...

  3. 【转】.net框架读书笔记---CLR内存管理\垃圾收集(一)

    一.垃圾收集平台基本原理解析 在C#中程序访问一个资源需要以下步骤: 调用中间语言(IL)中的newobj指令,为表示某个特定资源的类型实例分配一定的内存空间. 初始化上一步所得的内存,设置资源的初始 ...

  4. 【转】.net框架读书笔记---CLR内存管理\垃圾收集(五)

    对象复苏     当一个终止化对象被认为死亡时,垃圾收集器可以强制使该对象获得重生(进入终止化可达队列),因为这样才能调用对象的Finalize方法.在Finalize方法被调用之后,它才算真正的死亡 ...

  5. 【转】.net框架读书笔记---CLR内存管理\垃圾收集(二)

    前几天学习了CLR垃圾收集原理和基本算法,但是那些是仅仅相对于托管堆而言的,任何非托管资源的类型,例如文件.网络资源等,都必须支持一种称为终止化(finalization)的操作. 终止化 终止化操作 ...

  6. .net框架读书笔记---CLR内存管理\垃圾收集(二)

    前几天学习了CLR垃圾收集原理和基本算法,但是那些是仅仅相对于托管堆而言的,任何非托管资源的类型,例如文件.网络资源等,都必须支持一种称为终止化(finalization)的操作. 终止化 终止化操作 ...

  7. 【转】.net框架读书笔记---CLR内存管理\垃圾收集(七)

    编程控制垃圾收集器 System.GC类型为应用程序提供了直接控制垃圾收集器的一些方法,可以通过GC.MaxGeneration来查询托管堆支持的最大代龄,目前为2. 通过下面方法执行垃圾收集器 GC ...

  8. 《代码的未来》读书笔记:内存管理与GC那点事儿

    一.内存是有限的 近年来,我们的电脑内存都有好几个GB,也许你的电脑是4G,他的电脑是8G,公司服务器内存是32G或者64G.但是,无论内存容量有多大,总归不是无限的.实际上,随着内存容量的增加,软件 ...

  9. 《Linux内核设计与实现》读书笔记(12)--- 内存管理(2)

    6.slab层 为了便于数据的频繁分配和回收,Linux内核提供了slab层(也就是所谓的slab分配器).slab分配器扮演了通用数据结构缓存层的角色. slab层把不同的对象划分为所谓高速缓存(c ...

最新文章

  1. 开发日记-20190905 关键词 Linux (Ubuntu) 下的Android模拟器:Genymotion
  2. [@Controller]4 详解@ModelAttribute
  3. linux系统判断是否重启、关机、查询登录诊断分析简介
  4. mysql 日志文件 自动_自动恢复MySQL数据库的日志文件思路分享及解决方案
  5. export LD_LIBRARY_PATH 的使用
  6. Effective Java~26. 不要使用 raw type
  7. c 语言 timestamp,c中的时间戳,精度为毫秒
  8. java中数组的定义
  9. Quartz.NET作业调度框架详解
  10. 如何获得onblur中的值_使用带有onBlur的输入字段和来自Reactjs JSX中的状态块输入的值?...
  11. oracle查询:分组查询,取出每组中的第一条记录
  12. 不是纸上谈兵,VR原来真的可以缓解抑郁症
  13. python 逻辑回归sklearn_python – 分类:使用sklearn进行PCA和逻辑回归
  14. 浅析GestureDetector
  15. 页面404圈小猫游戏代码
  16. 搭建博客mysql 结构_LANP环境构架搭建
  17. 1024(Windows考点整理)
  18. 外显子和基因组基本概念(二)
  19. R语言读取文件报错之二:Error in read.table(“xxxx.txt“, header = TRUE) : 列的数目比列的名字要多
  20. 查找文件及文件内容查找

热门文章

  1. 【C语言进阶深度学习记录】三十九 C语言中的可变参数(参数可变的函数)
  2. 【OS学习笔记】三十一 保护模式九:页目录、页表和页三者的关系详解
  3. Java 中的 Reference
  4. [Linux] linux下安装配置 zookeeper/redis/solr/tomcat/IK分词器 详细实例.
  5. docker 查询或获取私有仓库(registry)中的镜像
  6. 20172327 2018-2019-1 《程序设计与数据结构》第八周学习总结
  7. extern、static
  8. 每天五分钟,玩转Docker。-Day2
  9. C# ADO.NET
  10. 海康、大华IPC的rtsp格式