转载

Java虚拟机之垃圾回收器(GC)

本文内容来自《深入理解Java虚拟机》,主要是自身学习,用于记录重点,方便回忆,复习。对应《深入理解Java虚拟机》第三章,记录GC的算法,特点,常用GC收集器。

虚拟机系列一: Java虚拟机之内存

一、对象可以被回收??

垃圾回收器的主要作用是回收无用的对象空间,那么怎么判断对象是否已经无用了呢??主要有两种算法。

1、引用计数法

对象增加一个计数器,当有引用(变量)指向该对象是,计数器加一,但引用不再指向该对象,计数器减一,计数器为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,未能被回收
    }
}复制代码

2、可达性分析法

从CG Roots出发,向下搜索,所走过的路径称为引用链,当一个对象没有在任何引用链上,则此对象可被回收。

GC Roots的对象包括以下引用:

(1)虚拟机栈(方法中局部变量指向的引用)中引用的对象。

(2)方法区中类静态属性引用的对象。

(3)方法区中常量引用的对象。

(4)本地方法区栈中JNI应用的对象。

补充:

可达性分析不可达的对象不会立即被回收,还得进过 两次标记 过程。1、第一次标记为筛选对象是否必要执行finalize()方法(对象没有覆盖finalize,或已经执行过则为非必要)。2、如果1结果为必要,则放入F-Queue队列中,虚拟机会建立低优先机线程调用,不保证一定执行完finalize(是对象最后的复活机会)。

二、引用

1、强引用

类似Object obj = new Object(),不会被垃圾回收器回收。

2、软引用

有用但非必须的对象,在系统将要发生内存溢出前,把这些对象列进回收范围,进行第二次回收。通过 SofeReference 类实现。

3、弱引用

非必须对象,强度比软引用弱,发生垃圾回收,无论内存是否足够,都会回收对象。通过 WeakReference 实现

4、虚引用

幽灵引用、幻影引用,最弱的一种引用。唯一的用处是,垃圾回收时会收到一个系统通知,通过 PhantomReference 实现。

三、垃圾回收算法

1、标记-清除算法

标记出内存中可被回收的对象,回收相应的对象。主要有两个不足:1、效率问题,标记、清除效率都不高。2、空间碎片化,会有大量不连续的内存碎片。

2、复制算法

将内存划分为大小相等的两块、一块为空闲面,一块为对象面。回收是减对象面中不能被回收的对象复制到空闲面,清除对象面内所有对象。此时的清除后的块为空闲面。 使用于对象存活率低场景,少量复制,清除所有空间。

3、标记-整理算法

对不能被回收的对象进行标记,整理到连续的空间上,清除掉余下空间。

Java虚拟机中机制

采用分代收集算法,把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

1、Serial收集器(-XX:+UseSerialGC)

单线程收集器,工作时,必须暂停其他所有工作线程。Client模式下的默认年轻代(新生代)收集器,简单高效。

2、ParNew收集器(-XX:+UseParNewGC)

Serial收集器的多线程版,指定参数-XX:UseConcMarkSweepGC选项后,默认新生代收集器就会是ParNew,通过-XX:ParallelGCThreads限制垃圾收集器线程数。

3、Parallel Scavenge收集器(-XX:UseParallelGC)

吞吐量(运行用户代码时间/cpu时间(垃圾收集器工作时间+用户代码运行时间))优先的收集器。适合后台运算而不需要太多交互任务。-XX:MaxGCPauseMillis控制垃圾收集器最大停顿时间,-XX:GCTimeRatio((0,100)整数,工作时间/垃圾时间,如19 ,则工作时间占比为19/19+1 )吞吐量大小。-XX:+UseAdaptiveSizePolicy虚拟机会根据系统情况自动调整各参数。

4、Serial Old收集器(-XX:+UseSerialOldGC)

serial的老年代收集器,单线程、标记-整理算法。

5、Parallel Old收集器(-XX:UseParallelOldGC)

Parallel Scavenage,多线程、标记-整理算法,吞吐量优先。

6、CMS收集器(Concurrent Mark Sweep)

追求停顿时间短、标记-清除算法、过程包括:

1、初始化标记(Stop The World 停止工作线程)

2、并发标记

3、重新标记(Stop The World 停止工作线程)

4、并发清除

缺点:标记-整理算法,容易碎片化。

配置参数

-XX:+UseCMSCompactAtFullCollection ,顶不住,需要Full GC时开启内存合并整理。

-XX:+CMSFullGCsBeforeCompaction  设置多少次不压缩的Full GC后进行GC压缩,默认为0,即每次Full GC都进行碎片整理。

7、G1收集器(Garbage-First)-XX:UseG1GC

复制+标记-整理,整体复制-整理算法,局部复制算法

原文  https://juejin.im/post/5cbfc4715188250aa776718e
正文到此结束
Loading...