JVM GC回收原理的认识
在我们进行性能测试的时候,GC/FullGC次数常作为内存性能指标的一项来进行考察,过于频繁的FullGC是性能存在问题的一种表现。
1.什么是GC
JVM中垃圾回收机制是由垃圾收集器Garbage Collection GC来实现的,GC是后台的守护进程,它是在内存中低到一定限度时才会自动运行,从而实现对内存的回收。这就是垃圾回收的时间不确定的原因。
GC也属于进程,也需要消耗CPU等资源。如果GC执行过于频繁会对JAVA程序的执行产生较大的影响。
2.年轻代和年老代
JVM把堆分为了两种:年轻代和年老代。
为什么要进行分代呢?JVM的创建的对象有很多都是一次性的,用完一次就扔的那种(80%左右);但也存在需要重复多次使用的对象。如果没有区分,所有的对象都在一块,那么在进行GC的时候需要对所有对象进行全盘扫描,以区分哪些需要回收,哪些需要保留。因此,我们在分代的时候,将新创建的对象全部分到一个单独的分区上,每次GC的时候先对这块存有那些“朝生夕死”的对象进行回收——这块区域就称作年轻代;而另一个区域中则放了一些多次保留的“老油条”,称作年老代。
3.Minor GC和 Full GC
年轻代分为三个区:一个Eden区和两个Survivor区。年老代只有一个Old分区。
一个新的对象刚创建的时候,是存放在Eden区中的。From分区中可能存放有一些之前存活下来的对象,To分区中置空。
当该区中的对象达到饱和时,会进行一次GC,GC范围是针对年轻代中3个分区的,叫做Minor GC。
在进行Minor GC的时候,除了对Eden和From分区中的垃圾对象进行回收,还需要将存活下来的对象进行安置:Eden中的存活对象直接放入To分区中,From中的存活对象会先判断存活对象的年龄(对象每经过一次GC存活,年龄+1),达到一定年龄阈值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被丢到Old分区,而没有到年龄阈值的则被移到To分区。当To分区也被填满的时候,则将To分区中所有对象移动到年老代Old中。
以上就完成了一次Minor GC,再进行下一次Minor GC的时候,From和To会交换角色,其他同理。
而当Old分区中的对象满了的时候,则会对年轻代和年老代中的所有分区进行GC,会占用更多的资源和时间。这个叫做FullGC。