本文内容来自《深入理解Java虚拟机》,主要是自身学习,用于记录重点,方便回忆,复习。对应《深入理解Java虚拟机》第三章,记录GC的算法,特点,常用GC收集器。
虚拟机系列一: Java虚拟机之内存
垃圾回收器的主要作用是回收无用的对象空间,那么怎么判断对象是否已经无用了呢??主要有两种算法。
对象增加一个计数器,当有引用(变量)指向该对象是,计数器加一,但引用不再指向该对象,计数器减一,计数器为0即可回收。Java虚拟机未使用该方法,主要是由于该方法很难解决循环应用问题。如下:
class GcTest{ Object obj; public static void main(){ GcTest objA = new GcTest(); GcTest objB = new GcTest(); objA.obj = objB; objB.obj = objA; objA = null; objB = null; //此种情况下使用,应用计数法,对象objA,objB的计数均为1,未能被回收 } }复制代码
从CG Roots出发,向下搜索,所走过的路径称为引用链,当一个对象没有在任何引用链上,则此对象可被回收。
GC Roots的对象包括以下引用:
(1)虚拟机栈(方法中局部变量指向的引用)中引用的对象。
(2)方法区中类静态属性引用的对象。
(3)方法区中常量引用的对象。
(4)本地方法区栈中JNI应用的对象。
补充:
可达性分析不可达的对象不会立即被回收,还得进过 两次标记 过程。1、第一次标记为筛选对象是否必要执行finalize()方法(对象没有覆盖finalize,或已经执行过则为非必要)。2、如果1结果为必要,则放入F-Queue队列中,虚拟机会建立低优先机线程调用,不保证一定执行完finalize(是对象最后的复活机会)。
类似Object obj = new Object(),不会被垃圾回收器回收。
有用但非必须的对象,在系统将要发生内存溢出前,把这些对象列进回收范围,进行第二次回收。通过 SofeReference 类实现。
非必须对象,强度比软引用弱,发生垃圾回收,无论内存是否足够,都会回收对象。通过 WeakReference 实现
幽灵引用、幻影引用,最弱的一种引用。唯一的用处是,垃圾回收时会收到一个系统通知,通过 PhantomReference 实现。
标记出内存中可被回收的对象,回收相应的对象。主要有两个不足:1、效率问题,标记、清除效率都不高。2、空间碎片化,会有大量不连续的内存碎片。
将内存划分为大小相等的两块、一块为空闲面,一块为对象面。回收是减对象面中不能被回收的对象复制到空闲面,清除对象面内所有对象。此时的清除后的块为空闲面。 使用于对象存活率低场景,少量复制,清除所有空间。
对不能被回收的对象进行标记,整理到连续的空间上,清除掉余下空间。
采用分代收集算法,把Java堆分为年轻代、老年代。 年轻代 中每次回收都只有少量对象存活,适用 “复制算法” 。 老年代 存活率高、适用 标记整理算法。
年轻代中分为Eden区,还有两块Survivor区。
每次创建对象,使用Eden区及一块Survivor区。当垃圾回收时,将对象复制到另一块Survivor区,清除该Eden区及Survivor区数据。HotSpot虚拟机默认Eden:Survivor大小比例为8:1,也就是一块Survivor只有空间10%,回收时,当Eden区大量对象存活时,Survivor明显放不下。这时对象会被放入老年区。
进入老年区除以上情况还有,Survivor区中数据经过15次(默认,可配置)垃圾回收,仍未被回收,会将对象放入老年区。
新生代垃圾收集器: Serial (1) ParNew (2) Parallel Scavenage (3)
老年代垃圾收集器: CMS(可配合的新生的收集器为 1、2 ) Serial Old(可配合的新生的收集器为 1、2、3 ) Parallel Old(可配合的新生的收集器为 3 )
单线程收集器,工作时,必须暂停其他所有工作线程。Client模式下的默认年轻代(新生代)收集器,简单高效。
Serial收集器的多线程版,指定参数-XX:UseConcMarkSweepGC选项后,默认新生代收集器就会是ParNew,通过-XX:ParallelGCThreads限制垃圾收集器线程数。
吞吐量(运行用户代码时间/cpu时间(垃圾收集器工作时间+用户代码运行时间))优先的收集器。适合后台运算而不需要太多交互任务。-XX:MaxGCPauseMillis控制垃圾收集器最大停顿时间,-XX:GCTimeRatio((0,100)整数,工作时间/垃圾时间,如19 ,则工作时间占比为19/19+1 )吞吐量大小。-XX:+UseAdaptiveSizePolicy虚拟机会根据系统情况自动调整各参数。
serial的老年代收集器,单线程、标记-整理算法。
Parallel Scavenage,多线程、标记-整理算法,吞吐量优先。
追求停顿时间短、标记-清除算法、过程包括:
1、初始化标记(Stop The World 停止工作线程)
2、并发标记
3、重新标记(Stop The World 停止工作线程)
4、并发清除
缺点:标记-整理算法,容易碎片化。
配置参数
-XX:+UseCMSCompactAtFullCollection ,顶不住,需要Full GC时开启内存合并整理。
-XX:+CMSFullGCsBeforeCompaction 设置多少次不压缩的Full GC后进行GC压缩,默认为0,即每次Full GC都进行碎片整理。
复制+标记-整理,整体复制-整理算法,局部复制算法