【Java】了解GC过程
·
这个视频一看就能懂!!!
【java】10分钟,了解GC过程 https://www.bilibili.com/video/BV1dt411u7wi
引用一条评论关键问题:
“面试官问了一个这样的问题,YoungGC触发时会发生什么,我回答E区和S0区存活的对象会复制到S1区,然后清理E区和S0区,下一次GC时E区和S1区存活对象会复制到S0区,以此交替(不考虑对象进入老年代)。面试官继续问:E区和S0区的所有存活对象都可以复制到S1区吗?S1区能放下这么多对象吗?E区和S0区清理是整个删除吗?”
问题1:E区和S0区的所有存活对象都可以复制到S1区吗?
“不一定都能复制过去,主要有以下几种情况:”
// 1. 大对象直接进入老年代
// 如果对象大小超过-XX:PretenureSizeThreshold阈值
byte[] largeObject = new byte[3 * 1024 * 1024]; // 3MB大对象直接进入老年代
// 2. 年龄达到阈值的对象进入老年代(Young GC 15次未被清理)
// -XX:MaxTenuringThreshold=15,默认年龄达到15进入老年代
问题2:S1区能放下这么多对象吗?
“S1区的大小是动态调整的,但确实可能放不下,这时候会触发担保机制:”
// 如果S1区空间不足,JVM会检查老年代剩余空间
if (老年代剩余空间 > 年轻代所有对象总大小) {
// 安全,直接进行Young GC
} else {
// 检查是否允许担保失败
if (-XX:-HandlePromotionFailure) {
// 不允许担保失败,直接进行Full GC
} else {
// 尝试Young GC,如果S1区真的放不下,部分对象会直接进入老年代
}
}
问题3:E区和S0区清理是整个删除吗?
“不是简单的删除,而是通过复制算法进行清理:”
// 假设内存布局:
// Eden区(80%) + S0区(10%) + S1区(10%)
public void youngGC() {
// 1. 标记存活对象(通过GC Roots可达性分析)
List<Object> survivingObjects = markSurvivingObjects();
// 2. 复制存活对象到S1区
for (Object obj : survivingObjects) {
if (canFitInS1(obj)) {
copyToS1(obj); // 复制到S1
} else {
promoteToOldGen(obj); // 晋升到老年代
}
}
// 3. "清理"实际上是重置指针,不是物理删除
edenPointer = edenStart; // Eden区指针重置到起始位置
s0Pointer = s0Start; // S0区指针重置
// 之前的数据还在内存中,但被标记为可覆盖
}
总结
- 不是所有对象都能复制到S1区:大对象会直接进入老年代,年龄达到阈值的对象也会晋升
- S1区大小问题:JVM有内存担保机制,如果S1区放不下:
先检查老年代剩余空间是否足够如果足够,进行Young GC,放不下的对象进入老年代如果不够,可能直接触发Full GC - 清理机制:不是物理删除,而是通过复制算法:
存活对象复制到S1区Eden和S0区的内存指针重置原有数据不会被立即擦除,而是等待被新对象覆盖
这种设计保证了内存整理的效率和空间的连续性。"
更多推荐
所有评论(0)