Java 垃圾收集器以及回收策略及其始末

来源:互联网 发布:美国10月非农数据预测 编辑:程序博客网 时间:2024/06/06 18:20

1. 引用计数法

优点: 简单,效率高。
缺点: 会出现双向引用,从而很难直接从计数算出是否可以回收

相关:Java可达性分析法:
GC roots : 方法区静态引用, 虚拟机栈内存, 本地方法区引用对象。
通过GC roots 遍历,即可得到所有不需要释放的对象。

1.1. 回收方法区

Java方法区放置很多常量, 已经静态变量, 常量如字符串, 以及无用的已加载的类机器码。


2. 回收策略

2.1 标记-清除算法

通过某种方法把所有的的垃圾对象进行标记, 然后统一回收。
缺点:碎片太多。

2.2 复制算法

为了解决尚需碎片化问题, 把可回收的内存对象进行复制
缺点:复制太多, 代价过大。

Java使用分代算法,老年代,和新生代
新生代策略: 由于新生代可释放变量统计为98%左右, 因此,hotSpot虚拟机使用一个大内存Eden, 和2个小内存Survivor, 比例为8:1, 其回收过程是每次回收,将无需回收的放入到一个Survivor内存中,其他的全部释放。 如果在极端情况下(如新生代超过10%内存不需要回收), 需要老年代来分担一部分。

老年代策略: 由于老年代一般回收频率, 可使用标记-复制算法来回收。


3. 回收时机

3.1 枚举根节点

Java虚拟机一般在安全区(不会出现引用变化指令) 设置安全节点来在GC时间的时候相关线程在安全区的区域内或者安全点, 从而进行GC回收,由于设置了安全点, GC将会特别快。
GC时期的抢断式中断:把所有线程进行中断, 未到安全区的进入安全点后中断,从而GC
缺点:真正的stop the world, 需要依据当前判断并且设置很多的安全点

GC时期的主动式抢断:设置标记,然后其他线程轮询看拥有GC标记,直到安全区后,中断。所有线程都到安全区后,进行GC。


4. 相关收集器


4.1 Serial收集器

原理:必须要Stop the world的方式, 让所有线程达到安全区后,进行GC。
缺点:会让程序停止,多线程,资源消耗大的情况下等待时间比较长。
优点:简单,高效,在Client,并且单线程的情况下,在程序可用性允许下很高效。

4.2 ParNew收集器

Serial收集器的多线程版本,收集的时候多线程同时进行。

4.3 Parallel Scavenge收集器

并行回收, 也必须stop the world, 是ParNew的优化版,可以通过设置参数, 并且虚拟机会自适应的优化。这是最大的区别。

4.4 Serial old 收集器

原理和Serial一致,不过服务于老年代对象。

4.5 Parallel Old收集器

同理也是并发进行,服务器老年代对象

4.6 CMS 收集器

原理:分为:初始化标记,并发标记, 重新标记,并且清除过程。
其中,初始标记和重新标记需要stop the world。
功能: 初始化标记为标记GC root引用对象
并发标记:标记GC root的各种深层引用, 比较耗时,但是可与程序并行。
重新标记:根据之前并发时期的时候运行过程,标记修改的引用的部分的标记。
并发清除:清除之前已经标记删除的对象。

优点:把停顿时间减少很多,而且并发执行。
缺点:减少了吞吐量,需要用更多的CPU资源来GC, 而且并发清除时间段,会产生很多
浮动垃圾, 而且这种收集器使用标记-清除算法,并不是标记-整理-清除,因此内存会碎片化


4.7 G1收集器

适用于新老年代的收集器,于JDK1.7版之后可使用
G1在CMS执行步骤上差不多, 并且在这基础上 算法 为 标记-整理,因此碎片化问题减少,
目前1.8版本可以看到默认使用G1收集器,只从逻辑上区分新老年代,而不是之前的物理隔
离,可选择使用三色标记算法(golang目前使用的垃圾回收机制), 并添加了专门用于存储
大内存块区域。


4.8 相关参数设置




5. 观点

1. 了解一种成功语言的垃圾回收机制的由来(并且历史悠久),对学习其他语言的回收机制很有帮助,从而可以达到通透GC算法的优缺点。
2. 了解这些GC算法的始末,可对其优缺点和生产环境相结合,从而进行调优。


阅读全文
0 0
原创粉丝点击