秒懂JVM的垃圾回收机制

前言阅读过王子之前JVM文章的小伙伴们 , 应该已经对JVM的内存分布情况有了一个清晰的认识了 , 今天我们就接着来聊聊JVM的垃圾回收机制 , 让小伙伴们轻松理解JVM是怎么进行垃圾回收的 。
复制算法、Eden区和Survivor区首先我们就来探索一下对于JVM堆内存中的新生代区域 , 是怎么进行垃圾回收的 。
实际上JVM是把新生代分为三块区域的:1个Eden区 , 2个Survivor区 。
其中Eden区占用80%的内存空间 , 每块Survivor各占用10%的内存空间 。 比如Eden区有800M , 那么每个Survivor区就有100M 。
平时可以使用的区域是Eden区和其中一块Survivor区 , 也就是900M的内存空间 。
秒懂JVM的垃圾回收机制文章插图
秒懂JVM的垃圾回收机制文章插图
刚开始创建对象的时候 , 对象都是分配在Eden区中的 , 如果Eden区快满了 , 就会触发垃圾回收 Young GC , 使用的就是复制算法进行垃圾回收 , 流程如下:
首先会把Eden区中的存活对象一次性转入其中一块空着的Survivor区中 。
然后清空Eden区 , 之后新创建的对象就再次被放入了Eden区中了 。
如果下次Eden区快满了 , 就会再次触发Young GC , 这个时候会把Eden区和存在对象的Survivor区中存活的对象转移到另一块空着的Survivor区中 , 并清空Eden区和之前存在对象的Survivor区 。
这就是复制算法的流程 。
一直要保持一个Survivor区是空的以供复制算法垃圾回收 , 而这块区域只占用整个内存的10% , 其他90%的内存都能被使用 , 可见内存利用率还是相当高的 。
什么时候进入老年代接下来我们就来看一下什么时候会进入老年代 , 这个问题上篇文章轻松理解JVM的分代模型中已经简单的介绍过了 , 今天会对此展开进行详细探索 。
1.躲过15次GC后进入老年代
在默认的情况下 , 如果新生代中的某个对象经历了15次GC后 , 还是没有被回收掉 , 那么它就会被转入到老年代中 。
这个具体躲过多少次 , 是可以自己设置的 , 通过JVM参数“-XX:MaxTenuringThreshold”来设置 , 默认是15.
2.动态对象年龄判断
另一种判断方式也可以进入老年代 , 是不用等待GC15次的 。
它的大致规则是 , 假如一批对象总大小大于了当前Survivor区域内存的大小的50% , 那么大于等于这批对象年龄的对象就会被转移到老年代 。
小伙伴们可能觉得有些没看明白这句话的意思 , 没关系 , 我们看一下图
秒懂JVM的垃圾回收机制文章插图
秒懂JVM的垃圾回收机制文章插图
?
假设Survivor中有两个对象 , 它们都经历过2次GC , 年龄是2岁 , 而且两个对象加在一起的大小大于50M , 也就是超过了Survivor区域内存大小的50% , 那么这个时候 , Survivor区域中年龄大于等于2岁的对象就要全部转移到老年代中 。
这就是所谓的动态年龄判断规则 。
要注意的是 , 年龄1+年龄2+年龄n的多个年龄对象大小超过Survivor区的50% , 此时会把年龄n以上的对象放入老年代 。
3.大对象直接进入老年代
有一个JVM参数"-XX:PretenureSizeThreshold" , 默认值是0 , 表示任何情况都先把对象分配给Eden区 。
我们可以给他设置一个字节数1048576字节 , 也就是1M 。
它的意思就是当要创建的对象大于1M的时候 , 就会直接把这个对象放入到老年代中 , 压根不会经过新生代 。
因为大对象在经历复制算法进行GC的时候是会降低性能的 , 所以直接放入老年代就可以了 。
4.Young GC后存活的对象太多无法放入Survivor区


推荐阅读