图解垃圾算法,No,捡垃圾算法
对象生与死
今天不是给大家介绍对象的,给大家介绍下垃圾,因为垃圾会霸占内存,需清理之,今天我们聊聊 JVM 用什么方式回收垃圾的!先上图吧,我们看看对象的生命周期。
先解释几个名词:
新生代:快速生长,存放年纪比较小的对象。
老生代:存放年纪比较大的对象。
Surviror:回收新生代内存后容纳其余存活的对象,分为 From 区和 to 内存区。
新生的对象都在 eden 区,当 eden 区满时容纳不了大的对象,会触发 GC,如果对象还活着,小对象进入 From 区或者是 to 区,这两块区域有一块是空的,假设现在装对象是 from 区,那么,当 GC 后 from 区所有对象会复制到 to 区,并且清空 from 区域,存活对象年纪会增大一岁,当对象到达一定年纪之后,就会进入老年代了。如果对象比较大,Surviror 装不下,会直接进入老年代,如果老年代也装不下,会报错:堆内存溢出。
简单介绍垃圾生命周期后,我们看看垃圾清理算法。
引用计数法
引用计数法怎么判断一个对象是垃圾?就看是否有引用指向该对象。引用计数法表示如果一个对象有 1 个引用计数器就是 1,2 个引用计算器是 2,如果没有引用,计数器为 0,也就是垃圾对象。缺点是对象相互引用,对象无法回收。画图举个简单案例。
如上图代码:teacher 持自身引用同时持有 student 的引用,计数器为 2,student 持自身引用同时持有 teacher 的引用,计数器为 2,这叫相互引用,最终导致 teacher 或者 student 对象都无法被回收。所以现在垃圾回收器一般不采用引用计数法。
标记-清除法
标记-清除分两步,GC 线程先标记可达对象,当发生 GC 时,清除不可达对象。缺点是回收后内存碎片。
如上图,我们知道分配内存都是连续的,垃圾对象回收后,内存很不规则,不利于内存使用效率。垃圾对象是不可达的?那什么叫可达对象呢,什么叫不可达对象呢?
可达对象:从根引用搜索,能达到的对象叫可达对象,如绿色存活对象叫可达对象。如果从根引用搜索,
不可达对象:不能达到的对象叫不可达对象。如黄色部分,就是垃圾对象,特别注意:此黄非彼黄。
根引用:也叫 GC root,存放在栈中,指向堆的引用,一般用参数或者局部变量表示。
理论性的东西还是比较难理解,我们画图表示下。
假设:new Object()对应的堆地址是 0xJL。
Object object = new Object(); 栈 object 引用指向 new Object()对应的 0xJL 地址,new Object()对象可达,其中 object 就叫做根对象。
object = null; 告诉 gc 线程,没有引用指向 0xJL 了,那这块内存就有可能被标记为垃圾对象。
复制算法
复制算法需要将一块空白的内存一分为二,GC 后,将可达对象全部移动到另一块内存。新生代对象朝生夕死,GC 后将活着的对象移动到另一块空内存,并将当前使用的内存清空。每次 GC,循环往复。
如上图:新生代采用复制算法,GC 回收前使用 from 区域,GC 后使用 to 内存区域。
标记整理法
标记整理算法基于标记清除算法做了一定优化,gc 线程首先从根节点开始标记可达对象,并将可达对象压缩到内存顶部,最后清除边界区域,老年代对象生命周期长,比较适用于标记整理算法。
如上图:当老年代满了,会触发 Full GC,将内存压缩整理。
总结
画图解释了几种 GC 算法的含义和缺点,希望对你有帮助,喜欢的请点赞加关注哦。点关注,不迷路,我是【叫练】公众号,微信号【jiaolian123abc】边叫边练。
版权声明: 本文为 InfoQ 作者【叫练】的原创文章。
原文链接:【http://xie.infoq.cn/article/2b0d54faec8d9030c90d81054】。文章转载请联系作者。
评论