1.新生代GC(复制算法)
最开始是将新生代分为两个区域来实现的,
每当GC之后都会留下一些不连续的空间,这些碎片不利于新加入的大对象存放,因为大对象存放是需要一块连续空间的.所以每次GC完之后会将这些存活的对象排列复制到另一块空的内存中,然后直接把之前的那一块内存直接清空
但分为两块导致内存的利用率只有50%
后面对这个设计进行了升级演化出了
Eden区和两块Survivor区
2.Eden区和Survivor区(简称E区和S区)
Eden:翻译过来是伊甸园 一般占比80%内存可以通过参数-XX:SurvivorRatio这个参数来调整 默认值为8
Survivor:翻译过来是幸运者区的意思 有两块一般是各占比总内存的10%内存
有点类似读写分离的感觉
新建的对象都往Eden区存放
当E区存放不下对象时,就会发生一次GC
将E区和S区存活下来的对象复制到另一块S区,然后清空E区和当前这块S区
下一次GC的时候就是空闲另外一块S区,二者交替
存活的对象每经历过一次GC就会大一岁
在默认情况下大于15岁就会从S区移入到老年代
-XX:MaxTenuringThreshold 可以设置多少岁进入老年代
3.S区移入老年代
当S区中的对象某几个年龄段的对象加起来超过了当前S区的50%时.这些大于等于这个年龄的对象都会被移入到老年代,也就是动态年龄机制
4.从E区直接到老年代
当GC之后发现E区的存活的单个对象就已经超过了S区最大空间时,该对象会被直接移入到老年代
还有一个配置是XX:PretenureSizeThreshold可以设置值 大于这个值的对象不会经过新生代,会被直接加到老年代
5.minor gc前的判断
会对老年代的内存做一次判断,GC前会判断老年代所剩下的内存是否大于新生代所有的对象
如果是小于的情况下会判断一个值是否开启-XX:HandlePromotionFailure参数(空间担保机制)
如果是开启 则会判断当前剩余内存是否大于历史新生代平均每次GC之后存活下来的对象
如果是大于的话 就会继续执行minor GC 如果是小于的话老年代会做一次Full GC 然后再执行minor gc
如果minor gc的时候还是发现老年代剩下的内存还是小于新生代的对象的话就会发生OOM 堆内存溢出
6.老年代Full gc(标记整理算法)
将存活的对象移动,移到到一边紧凑的靠着(减少内存碎片)
Full gc比minor gc会慢10倍
jvm参数调优主要是保证尽量不进行full gc以及尽量保证E区gc之后存活的对象被移入到S区