当需要排查各种内存溢出, 内存泄漏等问题时, 当垃圾收集成为系统达到更高并发的瓶颈时, 我们有必要深入 GC 的原理.
image.png
常见垃圾回收算法
在查看垃圾回收具体过程的时候, 运行程序加上:
-XX:+PrintGCDetails 打印详细的垃圾回收过程.
程序计数器, 虚拟机栈, 本地方法区是三个区域随着线程创建而创建, 线程的销毁而销毁, 不在垃圾回收的范围内. 垃圾回收的区域主要集中在堆与方法区中.
引用计数法
给对象中添加一个引用计数器, 每当有一个地方引用它时, 计数器就加 1; 当引用失效的时候, 计数器就减 1; 任何时刻计数器为 0 的对象就是不可能再被使用的.
客观说: 引用计数器实现简单, 判定效率也足够高, 在部分情况下是一个不错的算法. 但 JVM 并没有使用引用计数法来管理内存.
可达性分析算法
主流的商业语言 (Java,C#) 都是通过可达性分析来判定对象是否存活的.
算法思路: 通过一系列称为 GC Roots 的对象作为起始点, 从这些节点开始向下搜索, 搜索所走过的路径称为引用链(Reference Chain), 当一个对象到 GC Roots 没有任何的引用链,(也就是从 GC Roots 到这个对象不可达), 那么证明此对象是不可用的.
如图: object5,object6,object7 虽然互相有关联, 但他们到 GC Roots 是不可达的, 所以他们会被判定为可回收的对象.
image.png
Java 中可作为 GC Roots 的对象:
虚拟机栈(栈帧中的本地变量表引用的对象)
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中 JNI(Native 方法)引用的对象
标记 - 清除算法
如名字分为两个阶段:
标记: 首先标记所有需要回收的对象, 在标记完成之后统计回收所有被标记的对象, 它的标记过程即为上面的可达性分析算法.
清除: 清除所有被标记的对象
缺点:
效率不足, 标记和清除效率都不高
空间问题, 标记清除之后会产生大量不连续的内存碎片, 导致大对象分配无法找到足够的空间, 提前进行垃圾回收.
复制算法
将可用的内存按容量划分为大小相等的 2 块, 每次只用一块, 当这一块的内存用完了, 就将存活的对象复制到另外一块上面, 然后把已使用过的内存空间一次清理掉.
缺点:
将内存缩小了原本的一般, 代价比较高
大部分对象是 "朝生夕灭" 的, 所以不必按照 1:1 的比例划分.
现在商业虚拟机采用这种算法回收新生代, 但不是按 1:1 的比例, 而是将内存区域划分为 eden 空间, from 空间, to 空间 3 个部分.
其中 from 空间和 to 空间可以视为用于复制的两块大小相同, 地位相等, 且可进行角色互换的空间块. from 和 to 空间也称为 survivor 空间, 即幸存者空间, 用于存放未被回收的对象.
在垃圾回收时, eden 空间中的存活对象会被复制到未使用的 survivor 空间中 (假设是 to), 正在使用的 survivor 空间 (假设是 from) 中的年轻对象也会被复制到 to 空间中 (大对象, 或者老年对象会直接进入老年带, 如果 to 空间已满, 则对象也会直接进入老年代). 此时, eden 空间和 from 空间中的剩余对象就是垃圾对象, 可以直接清空, to 空间则存放此次回收后的存活对象. 这种改进的复制算法既保证了空间的连续性, 又避免了大量的内存空间浪费.
标记 - 压缩算法
在老年代的对象大都是存活对象, 复制算法在对象存活率教高的时候, 效率就会变得比较低. 根据老年代的特点, 有人提出了 "标记 - 压缩算法(Mark-Compact)"
标记过程与标记 - 清除的标记一样, 但后续不是对可回收对象进行清理, 而是让所有的对象都向一端移动, 然后直接清理掉端边界以外的内存.
这种方法既避免了碎片的产生, 又不需要两块相同的内存空间, 因此, 其性价比比较高.
分代收集算法
根据对象存活的周期不同将内存划分为几块, 一般是把 Java 堆分为老年代和新生代, 这样根据各个年代的特点采用适当的收集算法.
新生代每次收集都有大量对象死去, 只有少量存活, 那就选用复制算法, 复制的对象数较少就可完成收集.
老年代对象存活率高, 使用标记 - 压缩算法, 以提高垃圾回收效率.
最后
限于篇幅, 先介绍常见的垃圾回收算法.
参考
如何解决 OutOfMemoryError?
多线程之 Java 内存模型(一)
JVM 垃圾回收器工作原理及使用实例介绍 https://www.ibm.com/developerworks/cn/java/j-lo-JVMGarbageCollection/
垃圾收集器第一部分 https://www.ibm.com/developerworks/cn/java/j-ibmjava2/
JVM 内存管理及垃圾回收 https://blog.csdn.net/zhangerqing/article/details/8214365
来源: http://www.jianshu.com/p/2b954a92d00b