GC 原理介绍

本文深入探讨了Java垃圾收集(GC)的原理,包括哪些区域需要回收,对象如何分配,如何判断对象是否可回收,以及各种GC算法和收集器的工作方式。重点关注了新生代和老年代的内存管理,如复制算法、标记-清除和标记-整理算法的应用。同时,文章详细介绍了CMS和G1收集器,分析了它们的优缺点以及如何通过参数调整GC行为。
摘要由CSDN通过智能技术生成

上一篇文章我们了解JVM内存模型,由于jvm的空间是有限的,为了降低接口响应时间,防止出现了内存溢出问题,难以定位错误的原因所在,这一篇总结一下gc回收的原理。

一、那些区域需要回收
我们知道程序计数器、虚拟机栈、本地方法栈,属于线程私有。由线程而生,随线程而灭,其中栈中的栈帧随着方法的进入顺序的执行的入栈和出栈的操作,一个栈帧需要分配多少内存取决于具体的虚拟机实现并且在编译期间即确定下来【忽略JIT编译器做的优化,基本当成编译期间可知】,当方法或线程执行完毕后,内存就随着回收,因此无需关心。

而Java堆、元空间则不一样。元空间存放着类加载信息,但是一个接口中多个实现类需要的内存可能不太一样,一个方法中多个分支需要的内存也可能不一样【只有在运行期间才可知道这个方法创建了哪些对象没需要多少内存】,这部分内存的分配和回收都是动态的,gc关注的也正是这部分的内存。

二、对象分配

当创建一个对象之后,在大多数情况下, 对象在新生代Eden区中分配, 当Eden区没有足够空间分配时, VM发起一次Minor GC, 将Eden区和其中一块Survivor区内尚存活的对象放入另一块Survivor区域, 如果在Minor GC期间发现新生代存活对象无法放入空闲的Survivor区, 则会通过空间分配担保机制使对象提前进入老年代(空间分配担保见下)。

-XX:PretenureSizeThreshold 对象直接在old区分配内存的阀值
年轻代中当搜集器为Serial和ParNew时,-XX:PretenureSizeThreshold的参数, 令大于该值的大对象直接在老年代分配,该值默认为0,意思是无论值多大都现在Eden中存放,除非Eden区不能存放该值的时候才在老年代存放。 这样做的目的是避免在Eden区和Survivor区之间产生大量的内存复制(大对象一般指 需要大量连续内存的Java对象, 如很长的字符串和数组), 因此大对象容易导致还有不少空闲内存就提前触发GC以获取足够的连续空间。

对象晋升

-XX:MaxTenuringThreshold 晋升年龄的阀值

对象在Eden出生如果经第一次Minor GC后仍然存活, 且能被Survivor容纳的话, 将被移动到Survivor空间中, 并将年龄设为1. 以后对象在Survivor区中每熬过一次Minor GC年龄就+1. 当增加到一定程度(-XX:MaxTenuringThreshold, 默认15), 将会晋升到老年代。

动态年龄的判断:
-XX:TargetSurvivorRatio
目标存活率,默认为50%。VM并不总是要求对象的年龄必须达到MaxTenuringThreshold这个年龄才会晋升。年龄从小到大进行累加,当加入某个年龄段后,累加和超过survivor区域TargetSurvivorRatio的时候,就从这个年龄段网上的年龄的对象进行晋升。假如没有设置TargetSurvivorRatio这个值,当年龄为1的值为35%,年龄2的值为25%。年龄为1和年龄为2的加起来超过50%,故年龄为2的和年龄大于2的都晋升为老年代。

三、如何判断是否可以回收

在这里插入图片描述

当一个对象到 GC Roots 没有任何引用链相连时, 即该对象不可达, 也就说明此对象是不可用的, 如下图: Object5、6、7 虽然互有关联, 但它们到GC Roots是不可达的, 因此也会被判定为可回收的对象。

在Java, 可作为GC Roots的对象包括:

1、虚拟机栈(栈桢中的本地变量表)中的引用的对象,就是平时所指的java对象,存放在堆中。
2、方法区中的类静态属性引用的对象,一般指被static修饰引用的对象,加载类的时候就加载到内存中。
3、方法区中的常量引用的对象。
4、本地方法栈中JNI(native方法)引用的对象。

即使在可达性分析算法中不可达的对象, VM也并不是马上对其回收,需要以下的条件:
1.可达性分析后没有发现引用链
2.查看对象是否有finalize方法且没被调用过,如果有重写且在方法内建立再建立引用,不会被回收。

四、垃圾收集算法和收集器

分代收集算法
这种算法会根据对象存活周期的不同将内存划分为几块, 如JVM中的 新生代、老年代、元空间. 这样就可以根据各年代特点分别采用最适当的GC算法。

新生代: 每次垃圾收集都能发现大批对象已死, 只有少量存活. 因此选用复制算法, 只需要付出少量存活对象的复制成本就可以完成收集。使用的搜集器为:Serial、ParNew、Parallel Scavenge 采用的算法都为复制算法。

老年代: 因为对象存活率高、没有额外空间对它进行分配担保, 就必须采用“标记—清理”或“标记—整理”算法来进行回收, 不必进行内存复制, 且直接腾出空闲内存。使用的搜集器为Serial Old、Parallel Old 采用的是“标记—整理”CMS收集器采用的是“标记—清理”算

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值