分代收集算法是JVM垃圾回收的机制,其实是【简单了解常见的GC算法】的综合应用。JVM的堆中存在许多对象,根据这些对象的生命周期(存活时间)可以将内存分为几个部分,eg:堆上的新生代和老年代,方法区的永久代。每个部分使用不同的GC算法进行垃圾回收,这就是分代收集算法。
新生代
顾名思义,新生代指新建对象存放的地方。一般来说,新建对象存放在新生代中,eg:局部变量。java程序中,90%以上的对象都是生命周期较短的,换句话说,90%以上的对象在新生代就回被回收掉。从前面文章可以知道,复制算法是非常适合这个场景的。新生代中分为3部分,1个eden区和2个survivor区(survivor0和survivor1),默认情况下,eden区与survivor区的比例为8:1:1。
复制算法的过程:程序创建对象发现eden区内存不够时,JVM的垃圾回收器将对eden区进行垃圾回收(Minor GC),将eden区中的不可回收的对象复制到survivor0区。如果survivor0区内存不够,则将survivor0区中不可回收的对象复制到survivor1区,然后将eden区和survivor0区中所有对象回收。
【JVM堆中的配置参数】
老年代
在新生代survivor区中生命周期足够久的对象将会晋升到老年代中,eg:缓存。生命周期足够久的概念:默认情况下经历了15次GC,或者超过-XX:MaxTenuringThreshold参数配置的次数;除此以外,如果对象需要的空间比较大,超出了eden区+1个survivor区的大小,或者超过-XX:PreternureSizeThreshold参数的值,也会直接进入老年代。一般来说,老年代内存空间比新生代大(默认老年代:新生代为1:2),老年代内存满后触发Full GC,使用标记-整理算法进行垃圾回收。Full GC花费的时间远长于Minor GC。
-Xmx40M -Xms40M -Xmn10M -XX:+PrintGCDetails
package com.su.mybatis.oracle.controller;
public class Test {
public static void main(String[] args) {
byte[] b = new byte[1024 * 1024 * 9 + 1];
}
}
输出结果:
Heap
def new generation total 9216K, used 876K [0x31d00000, 0x32700000, 0x32700000)
eden space 8192K, 10% used [0x31d00000, 0x31ddb148, 0x32500000)
from space 1024K, 0% used [0x32500000, 0x32500000, 0x32600000)
to space 1024K, 0% used [0x32600000, 0x32600000, 0x32700000)
tenured generation total 30720K, used 9216K [0x32700000, 0x34500000, 0x34500000)
the space 30720K, 30% used [0x32700000, 0x33000010, 0x33000200, 0x34500000)
compacting perm gen total 12288K, used 153K [0x34500000, 0x35100000, 0x38500000)
the space 12288K, 1% used [0x34500000, 0x345266f8, 0x34526800, 0x35100000)
ro space 10240K, 44% used [0x38500000, 0x38977808, 0x38977a00, 0x38f00000)
rw space 12288K, 52% used [0x38f00000, 0x3954e610, 0x3954e800, 0x39b00000)
永久代
永久代指方法区,存放类、静态变量、常量等,发生垃圾回收较少,当永久代中内存不足时,触发Full GC。
如果有写的不对的地方,请大家多多批评指正,非常感谢!