JVM简介(三)——GC
1.堆区从运行分配的角度分为java堆(用于对象内存的分配)和方法区(类信息等)。但是从另一个
视角,生命周期的角度,堆区分为年轻代、年老代、永久代。永久代即方法区。基本没有GC
Eden区 |
From区 |
To区 |
Old区 |
Perm区 |
一般对象都被创建在Eden区(特别大的会直接创建在Old区)
一次minor GC后仍存活的对象,会从Eden区被移到From区或To区
同样,From区会被移到To区或者To区会被移到From区
(所以具体移到哪个区看当前情况,一次minor GC后,Eden区和Survivor区中的某一个,一定是空的,一定是空的)
当经过一定次数(默认15次)的minor GC后仍然存活的对象,会被移到Old区
三。GC算法纬度
串行GC——暂停应用程序线程,使用单CPU进行处理
并行GC——暂停应用程序线程,使用多CPU,将任务分成多个子任务,并行处理
并发GC——不暂停应用程序线程,GC与应用程序并发处理
四。GC算法
图均转自CSDN
1.标记清除(Mark-sweep)——先标记不用的后清除。但是效率低、会产生大量碎片
2.复制(Copying)——内存分两块区域,每次只使用一块区域,GC时把正在使用的(即不能
被清除的)复制到另一块去。效率不错,且不会碎片化——需要两倍的空间
3.标记整理(Mark-Compact)——先标记不用的,然后压缩到一起。避免了碎片。
4.CMS——一般用于年老代
CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:
(1)初始标记(CMS-initial-mark):单线程,从GC Root寻找直达的对象,速度快,需暂停
(2)并发标记(CMS-concurrent-mark):与应用线程一起运行,是CMS最主要的工作阶段,
通过直达对象,扫描全部的对象,进行标记
(3)重新标记(CMS-remark):修正并发标记时由于应用程序还在并发运行产生的对象的修改,
多线程,速度快,需要全局停顿
(4)并发清除(CMS-concurrent-sweep):与应用程序一起运行
(5)并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。
CMS为何采用清除而不是压缩?
CMS主要关注低延迟,因而采用并发方式,清理垃圾时,应用程序还在运行,如果采用压缩,
则涉及到要移动应用程序的存活对象,此时不停顿,是很难处理的,一般需要停顿下,移动存活
对象,再让应用程序继续运行,但这样停顿时间变长,延迟变大 ,所以CMS采用清除算法。
五。算法选择
年轻代(Eden+Survivor To+Survivor From)使用复制(Copying)算法。可配置串行或并行。
年老代使用标记整理(Mark-Compact)算法。可选择串行。可配置串行或并行。另可配置为使用CMS
六。垃圾检测算法
1.引用计数法——给一个对象添加引用计数器,每当有个地方引用它,计数器就加1;引用失效就减1。
但是,如果我有两个对象A和B,互相引用,除此之外,没有其他任何对象引用它们,实际上这
两个对象已经无法访问,即是我们说的垃圾对象。但是互相引用,计数不为0,导致无法回收
2.可达性分析算法——以根集对象为起始点进行搜索,如果有对象不可达的话,即是垃圾对象。
这里的根集一般包括java栈中引用的对象、方法区常良池中引用的对象、本地方法中引用的对象等。
七。关于持久代
Java8开始。持久代被移除了,改用Metaspace。底层存储应该还是堆,只不过分开管理,单独的
内存分配单独的GC等。脱离开JVM调优范围。