GC

本文围绕JVM展开,介绍了堆中对象分配规则,一般对象分配在Eden区,经多次GC后达到阈值会放入老年代。还讲解了GC分类,包括部分回收和整堆回收。阐述了TLAB初衷,介绍多种垃圾收集器及适用场景,分析判断对象存活标准,最后对比了G1和CMS垃圾处理器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、关于堆中对象分配的规则?
jvm中 将对象分配在堆上,而堆又分为yonggen(Eden、from、to)、oldgen、metaspace,一般情况下对象分配在eden区,Eden区满了之后进行 minor gc(此时对from区也gc),将存活的对象转到to区,之后若eden再满再gc,反反复复知道某对象一直在from 或者to区 存活了多轮gc之后达到某个阈值,则将对象放入oldgen。 然而还有很多特殊情况,比如eden和from区gc后对象无法放到to区,那么就只能放到老年代oldgen,老年代也放不下那么就只能触发major gc /fullgc了,要是gc还放不下那就是oom了。
2、讲一讲GC?
jvm中的gc主要分为两类:一是部分回收partial gc二是整堆full gc回收。
对新生代进行回收 minor gc 需要stop the word 会影响其他线程。
对老年代进行回收 major gc
对整堆进行回收 full gc
3、TLAB的初衷?
在堆上分配java对象时可能遇到这样的问题,多个线程分配对象时,那么宏观上来说应该对堆内存加锁,防止堆的内存分配指针同时被多个线程使用,从而造成分配混乱。TLAB是与线程相关的一块堆内存,准确来说是Eden的一块内存,仅仅供本线程使用,从而在此空间上的对象分配是不需要同步额外开销的。
4、你知道有哪些garbage collector ?分别适应哪些场景(试着从吞吐量 和响应时间即stw时间少 分析!)?
总体来说,有三种算法标记清理算法、复制算法、标记整理算法。标记清理会产生内存碎片,复制算法会一部分内存用来做交换,来存放存活的对象,由于老年代的对象生命周期较长,所以不适合用复制算法。标记整理不会产生内存碎片。
Serial 串行执行 收集新生代 对应Serial Old 收集老年代;
ParNew 收集新生代 是serial的多线程版本 很长一段时间和CMS配合工作。
Parallel 新生代收集器 Parallel Old 老年代收集器 jdk8 默认收集器 吞吐量优先
CMS 低延迟收集老年代 其收集要点:初始标记:从GC roots 标记直接引用的存活对象(stw 单线程)并发标记:用户线程与标记线程同时 进行, 从上一步标记的对象开始向下标记。注意由于是并发执行可能存在错标和漏标的情况。错标:即存活的对象其实就是垃圾,而在此次回收过程中难以得到回收,这就造成了浮动垃圾。漏标比较致命即本来应该标记为存活对象,(如果不进行处理)然而却被当成垃圾清洁。这就有了下一阶段。重新标记:引用关系发生变化的对象记录应该重新扫描标记。注意重新扫描标记并不会扫描未发生变化的对象。所以比并发标记快一点,但是也很费时间,并发标记已经对绝大部分的对象标记过了,不会重新扫描。并发清理:该阶段可以和用户线程一起。
5、判断对象存活的标准是什么?
栈中的变量、方法区中的变量和常量池中的常量等引用的对象。
6、你了解G1垃圾处理器吗?名字为什么叫G1 ?为什么 有了这么多经典垃圾收集器还要研发G1?你可能知道CMS收集步骤 试着比较他们的异同?
由于G1是将堆分成多个region,而每个region都有其回收价值(回收能够得到的空间大小、回收时间等等),G1会优先回收那些价值高的老年代对象。Garbage First 即G1。
现代业务复杂多变。
由我们之前的分析可知 漏标是致命错误不应该出现,因为这样会将存活对象当做垃圾清扫出内存。而出现漏标对象的原因:
(1)用户线程将灰色对象到白色对象的所有引用或者间接引用都删除
(2)插入了一个黑色对象到白色对象的引用。
cms 采用increment update将新增加对象记录。之后以这些对象为根扫描一遍避免漏标
G1采用snapshot at the begining 通过pre-writte -barrier将旧对象引用关系记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值