GC Root:由堆外指向堆内的引用
- 方法栈帧中的局部变量
- 已加载类的局部变量
- JNI handles
- 已启动且未暂停的Java线程
一、GC Root可达性分析的问题
多线程环境下,某些线程可能会将某对象的引用误置为null(误报,其他线程中这个对象正在被引用),或者没有将自己引用过的对象设置为被引用(漏报),可以用以下STW解决。
二、Stop the World(老年代回收有时会出现卡顿)
停止所有其他非GC的线程的工作,直至完成本次垃圾回收(本质上其他线程并不一定都被挂起暂停,只要运行在安全点,不会引起JVM堆栈变化的话就可以运行)
三、卡表机制
Minor GC可以只扫描新生代在堆中的内存空间,避免全堆扫描,但是当老年代中的对象引用了新生代中的对象时,回收新生代时需要扫描老年代造成全堆扫描(此时可以将老年代中的对象看成是CG Root)。
为了不对所有的老年代进行扫描,JVM将老年代划分为512字节的一张张卡片,用一张表标记每张卡是否可能引用新生代,Minor GC时只扫描可能引用新生代的卡(卡表中将其标识为脏卡,标志位置为非零)。
四、垃圾回收器
-
新生代:
Serial:单线程、复制算法
Parallel New:多线程并行、复制算法
Parallel Scavenge:多线程并行、复制算法、高吞吐(程序运行时间/程序运行时间+GC时间) -
老年代:
Serial Old:单线程、整理算法
Parallel Old:多线程并行、整理算法
CMS:多线程并发、清除算法、高速(Java9开始被G1取代) -
混合代:
G1:多线程并发、整理算法、(堆中不再划分为新生代老年代,而是分区域,计算每块区域的回收效益,优先回收效益高的,GC运行时间短且释放内存空间大的区域)
参考文章:
https://time.geekbang.org/column/article/13137