JVM 垃圾回收原理简述
JVM堆空间划分
JVM堆空间分为:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation)
年轻代分为:一个Eden区,2个相同的Survivor区。所有新对象都会在Eden区创建,如此划分主要是为了让生命周期短的对象尽量留在年轻代。当Eden区不足时,进行minor collection,把存活对象拷贝到survivor区。
垃圾回收具体流程
1. 对象在Eden区完成内存分配。
2. 如果Eden区已满,就会触发minor collection进行年轻代垃圾回收。
3. 当minor collection时,Eden区不能被回收的对象放入到其中一个空的survivor区,另一个survivor区不能被回收的对象也会被放入这个survivor区,始终保证一个survivor区是空的。
4. 上一步中,如果survivor区满了,这些则会被拷贝到老年代。或者survivor区未满,但是部分对象已经足够old,也会被放入old区(由参数-XX:MaxTenuringThreshold决定)。
5. 当Old区满后,无法将新生代中多次复制后依然存活的对象复制进去的时候,就会对老年代的内存空间进行一次full GC,所以根据应用程序对象存活时间,合理设置老年代和新生代空间比例,对JVM垃圾回收性能影响很大,JVM设置老年代和新生代比例参数:-XX:NewRatio。
注意:JDK8:默认新生代:老年代比例值是1:2;新生代大小=1/3堆空间大小。JDK8的堆:新生代、老年代、元空间。
判断哪些对象需要被回收
通常使用如下两种方法:
1. 引用计数器:通过一个对象的引用计数器来判断对象是否被引用。每当对象被引用了,计数器就加1,当引用失效,计数器减1。如果计数器为0,则说明对象不被引用,可以被垃圾回收。注意:计数器虽然实现简单,判断高效,但存在对象之间互相循环引用的问题,所以JVM不适合引用计数方式。
2. 可达性分析:采用GC Roots作为起点进行搜索,能够达到的对象都是存活的,不可达的对象可被垃圾回收。
具体过程:从线程栈帧中的局部变量或者方法区的静态变量出发,将这些变量引用的对象进行标记,然后看这些被标记的对象是否引用了其他对象,继续进行标记,所有被标记的对象都是被使用中的对象,而没有被标记的对象就是可以回收的垃圾对象。
垃圾回收算法
JVM对垃圾对象占用的空间进行回收,回收的三种方法:
l 清理:将垃圾对象占用内存清理掉,其实JVM不会真的对这些垃圾内存进行清理,而是将这些垃圾对象占用的内存空间标记为空闲,记录在一个空闲列表里,当应用程序需要创建新对象的时候,就从空闲列表中找一段空闲内存分配个新对象。
l 压缩:从堆对象头部开始,将存活对象拷贝放在一段连续的内存空间,那么其余空间就是连续的空闲空间。
l 复制:将堆空间分成两部分,只在其中一部分创建对象,当这部分空间用完的时候,将标记过的可用对象复制到另一个空间中。
JVM垃圾回收器算法
l 串行回收器
l 并行回收器
l 并发回收器CMS
1. 初始化标记(stop the world)
2. 并发标记(标记与处理任务并行)
3. 重标记(stop the world)
4. 并发清理
l G1回收器
版权声明: 本文为 InfoQ 作者【Mars】的原创文章。
原文链接:【http://xie.infoq.cn/article/ac5ccd7d5c90ecfaf718c22e6】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论