JVM:垃圾回收器与内存分配策略简介

判断对象是否已经死亡的算法

1,引用计数算法

    引用计数算法给对象添加一个引用计数器,每当一个地方引用它是时,计数值就增加一;当引用失效时,计数值就建一,技术器为0的对象不可能在被使用。但是主流的JVM里没有使用它的,原因是他很难解决对象之间互相循环引用的问题。

    例如对象objA和objB都有字段instance,objA.instance = objB,objB.instance = objA,除此之外这两个对象再无任何引用,实际上这两个对象已经不可能在被访问,但是因为相互引用,所以计数值不为0,无法收集他们。

2,可达性分析算法

    这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何的引用链相连时,证明此对象是不可用的,如图:

JVM:垃圾回收器与内存分配策略简介

虽然对象object5,object6,object7是相互关联的,但是他们到GC Roots不可达,所以是可回收的。

可以作为gc root的有:

1 、 虚拟机栈(栈帧中的本地变量表)中引用的对象。

2、 本地方法栈中JNI(即一般说的native方法)引用的对象。

3、 方法区中的静态变量和常量引用的对象。

常见的垃圾回收算法

1,标记-清除(Mark-Sweep)算法

    如同其名,它的回收有两个阶段,首先标记出所有的需要回收的对象,在标记完成后统一回收所有被标记的对象。它是一种最基本的回收方法,但他也有不足。一是效率不高,标记和清除的效率都不高,二是容易产生内存碎片(如图),碎片太多导致无法分配较大的对象时,就会提前触发另一次垃圾收集动作。后续的方法都是在它的基础上进行改进。

JVM:垃圾回收器与内存分配策略简介

2,复制算法

    将内存的区域划分为相同大小的两块,每次只是用一块,在一块使用完成后,将其中的存活对象存储到另一块中,再把已使用的内存空间全部清理掉,这样就不用考虑内存碎片化的问题了,只需要移动堆顶的指针就行。但是这样的缺点就是只有一般半的内存可用。

JVM:垃圾回收器与内存分配策略简介

    复制算法也是新生代使用的回收算法,IBM的一项研究表明,新生代中的对象98%是“朝生夕死”的,也就是存活对象只占了大概2%。所以没有必要按照1:1分配空间,而是将内存划分为一块较大的Eden空间和两块小的Survivor空间,每次使用Eden和一块Survivor。回收时,将Eden和Survivor中还存活的对象一次性的复制到另一块Survivor中,最后清理掉Eden和使用的Survivor。

    HotSpot虚拟机默认Eden和Survivot的内存大小比例为8:1,所以整个新生代中可用的空间容量为新生代总容量的90%。当然无法保证每次存活的对象只占不到10%,这时就可以通过分配担保机制使用老年代来继续存储。

三:标记-整理(Mark-Compact)算法

    进入老年代的对象一般都是存活率较高的,假如在一次对象回收的过程中全部的对象都存活,这时如果再用复制算法,那么需要的空间将是50%,浪费极高。所以老年代使用和标记-清除类似的方式,标记过程一样,但是后续操作不是直接清理,而是将可回收对象移动到内存的一端,然后清理掉另一端的其他剩余内存。如图:

JVM:垃圾回收器与内存分配策略简介

四:分代收集算法

    这算是对GC垃圾收集算法的一个总结,当前虚拟机大都采用分代收集算法(),当前堆中根据对象的存活周期将内存划分为了几块,一般分为新生代和老年代。新生代中大量的对象都会死去,所以使用复制算法复制少量的对象;而老年代中对象存活效率高,没有额外的空间进行分配担保而且为了效率,就必须使用标记-整理算法。

 

虚拟机给每个对象定义了一个对象年龄计数器,在对象在Eden创建并经过第一次Minor GC后仍然存活,并能被Suivivor容纳的话,将会被移动到Survivor空间,并对象年龄设置为1。每经历过Minor GC,年龄就增加1岁,当到一定程度(默认15岁,可以通过参数-XXMaxTenuringThreshold设置),就将会晋升年老代。 

 

Full GC频繁原因:

在 CMS 启动过程中,新生代提升速度过快,老年代收集速度赶不上新生代提升速度

在 CMS 启动过程中,老年代碎片化严重,无法容纳新生代提升上来的大对象

 

如何从新生代进入老年代:

1,大对象直接存入老年代,为了减少full gc,这个大小值可以设置。

2,长期存活的对象直接存入老年代,例如年龄超过15了,这个年龄值可以设置。

3,同等年龄的超过survivor的一般,大于这个年龄的进入老年代。

 

几种垃圾回收器:

Serial 新生代单线程

ParNew 新生代多线程

Serial Old 老年代单线程

Parallel Old 老年代多线程

CMS收集器(Concurrent Mark Sweep)标记-整理清除,希望停顿的时间最短可以用这个

 

参考:《深入理解Java虚拟机》