分代垃圾回收
将整个内存区域划分为两部分,一部分加新生代,一部分叫老年代
新生代划分为: 伊甸园,幸存区from,幸存区to
长时间使用存活的对象,就放老年代中
用完就可以删的对象放在新生代中
新生代垃圾回收比较频繁,耗时短,常用的是复制算法
老年代垃圾回收频率低,耗时长,常用的是标记整理算法
(事实上,这些垃圾回收算法都是混合使用的,不同垃圾回收器有不同实现)
流程:
创建新对象时,先使用伊甸园空间储存,
当伊甸园第一次占满后,触发新生代垃圾回收Minor GC
用可达性分析算法,进行标记,用复制算法,将有用对象复制到幸存区to,
让这些幸存对象 寿命+1 ,并清空伊甸园
然后交换幸存区from和幸存区to位置.
当再次创建对象还是使用伊甸园空间
当伊甸园再次占满后,触发新生代第二次垃圾回收Minor GC
这次除了伊甸园外,还会将幸存区from中的对象,使用 复制算法 到幸存区to中
将幸存的对象年龄+1,幸存区from和幸存区to交换
当对象年龄超过(默认15)时,会将该对象复制(晋升)到老年代(不同垃圾回收器最大寿命不同)
不断创建对象,当老年代空间都放不下的时,先触发一次Minor GC,如果GC后空间还是不足
就会触发老年代垃圾回收Full GC
老年代垃圾回收会对新生代和老年代的垃圾统一用 标记整理算法
当 GC时,会触发stop the world.暂停其他用户线程,等垃圾回收线程结束后再启动
原因: minor GC用复制算法,对象的地址会改变,
若垃圾回收时,还有线程操作,使用对象,会造成混乱
Minor GC暂停时间较短,因为一般很少有晋升或长久的对象,复制较少,大部分都会被释放
(当然,这里不是说只有复制算法才需要STW,实际上,所有垃圾回收算法都需要再某些阶段STW)
特例:
大对象直接晋升策略
当当前对象在新生代中肯定放不下并且老年代可以放下时
该对象可以直接晋升老年代,并且不会触发minor GC
当内存不满足,并且触发minorGC和FullGC中都不够的时候,就抛出 堆内存溢出 异常
单独线程内的内存溢出不会导致其他线程因此停止
相关vim参数
堆初始大小: -Xms
堆最大大小: -Xms或-XX:MaxHeapSize=
新生代大小: -Xmm或(-XX:NewSize=size+-XX:MaxNewSize=size)
幸存区比例(动态): -XX:InitialSurvivorRatio=ratio和-XX:+UseAdaptiveSizePolicy
幸存区比例: -XX:SurvivoRatio=ratio(默认为8m)
晋升阈值: -XX:MaxTenuringThreshold-threshold
晋升详情: -XX:+PrintTenuringDistribution
GC详情: -XX:+PrintGCDetial -verbose:gc
FullGC前MinorGC: -XX:+ScavengeBeforeFullGC