技术编程|GC垃圾回收的原理和涉及的几种算法

1? GC垃圾回收的原理?
其实垃圾回收的原理很简单:就是判断出死亡的对象 , 然后清除死亡的 , 留下存活的即可 。那么怎么判断对象已经死亡呢?常有的有以下两种:
1)引用计数法(Reference Counting):在对象中添加一个引用计数器 , 每当一个地方引用它时 , 计数器就加1;当引用失效时 , 计数器就减1;当引用计数为0时就会被回收 。但是它存在一个很大的问题就是循环引用:如下图 , 当实例化A时 , A会持有实例B , B会持有C , C持有A 。这样一来我们就会发现:如果需要回收A , 除了释放初始实例化引用 , 还需要释放C的引用 。但是由于ABC互相引用 , 所以就造成谁也无法释放 。主流的垃圾回收都没有采用这种判断方法 , 因为需要额外的工作来解决它(感兴趣的童鞋可以看看智能指针) 。
技术编程|GC垃圾回收的原理和涉及的几种算法
文章图片

文章图片

2)可达性分析算法(Reachability Analysis):在JAVA虚拟机中就是通过可达性分析法来判定对象是否存活的 。思路是通过“GC Roots”的对象(可以认为是确定固定存在的对象)作为起始点 , 然后从这些节点开始遍历所有引用链 , 如果某个对象没有GC Roots直接或间接的连接的话 , 这个对象(白色节点)就被认为程序中不再使用可以被回收了 。如下图:
技术编程|GC垃圾回收的原理和涉及的几种算法
文章图片

文章图片

【技术编程|GC垃圾回收的原理和涉及的几种算法】2 垃圾回收的几种算法?
标记清除:其分为“标记”和“清除”两个阶段 。首先标记出所有死亡的对象 , 然后把所有死亡的的对象进行清除操作 。如下图 , 我们可以清楚地看到 , 这种回收算法有一个很大的问题:造成很多的不连续内存碎片 , 这样一来 , 如果需要创建稍微大一点的对象 , 就很可能无法找到足够大的内存空间 。这就需要整个再进行一次标记整理来解决这一问题(耗时耗力) 。
技术编程|GC垃圾回收的原理和涉及的几种算法
文章图片

文章图片

标记整理:算法分为”标记-整理-清除“阶段 , 首先需要先标记出存活的对象 , 然后把他们整理到一边 , 最后把存活边界外的内存空间都清除一遍 。这个算法的好处就是不会产生内存碎片 , 但是由于整理阶段移动了对象 , 所以需要更新对象的引用 。
技术编程|GC垃圾回收的原理和涉及的几种算法
文章图片

文章图片

标记复制:算法分标记-复制两个阶段 。首先会标记存活的对象 , 完成后 , 该算法会把存活的对象都复制到一块新的空内存里去 。最后将原来的内存空间清空 。过程如下图 , 这个算法最大的问题就是需要很大的内存(实际用地 , 用于复制的内存空间) , 同时如果存活的对象非常多的话 , 标记和复制阶段都就会很慢 。同时也涉及到了对象位置改变需要更新引用 。尽管看起来问题很大 , 但是根据分代理论:弱分代假说里大多数对象生命周期短 , 这种情况下标记复制就很适合了(复制的存活对象少) 。至于内存消耗太大的问题 , java虚拟机通过将新生代分为一个Eden区与2个Survivo区 , 其中一个Survivo区用来复制 , 这样一来极大地提高了内存空间利用率 。
技术编程|GC垃圾回收的原理和涉及的几种算法
文章图片

文章图片


推荐阅读