Files
examination/topics/gc-special/gc-deep-dive/true_false.json
T

118 lines
8.2 KiB
JSON
Raw Normal View History

{
"topic": "gc-deep-dive",
"type": "true_false",
"schema_version": "1.0.0",
"generated": "2026-09-03T00:00:00Z",
"questions": [
{
"id": "tf-001",
"type": "true_false",
"difficulty": 2,
"tags": ["gc", "语言对比", "自动内存管理"],
"question": "判断以下陈述是否正确:C/C++ 需要程序员手动分配和释放内存(如 malloc/free 或 new/delete);Rust 并没有采用传统 GC,而是通过所有权(ownership)与借用检查在编译期自动管理内存;而 Go 则依赖自动垃圾回收(GC)。",
"answer": true,
"explanation": "正确。C/C++ 是无 GC 语言,必须手动管理堆内存,容易造成泄漏与悬垂指针。Rust 不属于传统垃圾回收模型,其内存安全由所有权与生命周期系统在编译期保证,运行时并不寄生 GC。Go 则内置了 GC,由运行时负责回收不再使用的堆对象。",
"source": null,
"related": []
},
{
"id": "tf-002",
"type": "true_false",
"difficulty": 1,
"tags": ["gc", "lang", "go"],
"question": "判断以下陈述是否正确:Go 语言和 C/C++ 一样,运行时都没有自动垃圾回收机制,必须由程序员手动调用 free 等接口释放内存。",
"answer": false,
"explanation": "错误。Go 是带 GC 的语言,其 runtime 会自动回收不再引用的堆对象,程序员无需(也无法直接)手动调用 free。C/C++ 才是需要手动管理的。这也是 Go 通常被称为带自动 GC 语言的原因。",
"source": null,
"related": []
},
{
"id": "tf-003",
"type": "true_false",
"difficulty": 2,
"tags": ["gc", "代价", "stop-the-world"],
"question": "判断以下陈述是否正确:启用 GC 会引入运行时代价,包括发生 STW(stop-the-world)暂停、额外约 5%~20% 的内存开销,以及额外的 CPU 开销。",
"answer": true,
"explanation": "正确。GC 的核心代价来自三个方面:1) 标记/整理阶段常需要 STW 暂停用户线程;2) 分代/复制区等机制通常需要额外 5%–20% 左右的堆内存作为缓冲或预留;3) 标记、写屏障与并发更新等日常操作会消耗 CPU。这三项是评估 GC 开销的基本指标。",
"source": null,
"related": []
},
{
"id": "tf-004",
"type": "true_false",
"difficulty": 2,
"tags": ["gc", "mark-sweep", "碎片"],
"question": "判断以下陈述是否正确:标记-清除(Mark-Sweep)算法回收时不会移动存活对象,因此能保持内存紧凑、不会产生内存碎片。",
"answer": false,
"explanation": "错误。标记-清除算法只做标记与回收,并不移动对象,因此存活对象之间的空闲块会零散分布,产生大量内存碎片。这是 Mark-Sweep 的固有缺点,也是它不适合老年代等“大对象存活多”场景的原因;通常需要搭配压缩或内存合并策略来缓解。",
"source": null,
"related": []
},
{
"id": "tf-005",
"type": "true_false",
"difficulty": 4,
"tags": ["gc", "copying", "复制算法", "老年代"],
"question": "判断以下陈述是否正确:复制(Copying)算法即使把存活对象拷贝到另一半空间,其拷贝成本与存活对象数量无关,因此非常适合在老年代等存活率很高的区域使用。",
"answer": false,
"explanation": "错误。Copying 算法需要把存活对象全部复制到另一半空间,复制工作量与存活对象数量成正比。当对象存活率高(如老年代)时,复制开销巨大、几乎每个对象都要被搬移,因此复制算法通常只用于年轻代(存活率低的区域),不适合对象存活率高的老年代(那里多用标记-压缩)。",
"source": null,
"related": []
},
{
"id": "tf-006",
"type": "true_false",
"difficulty": 3,
"tags": ["gc", "mark-compact", "标记-压缩", "碎片"],
"question": "判断以下陈述是否正确:标记-压缩(Mark-Compact)算法在回收的同时移动存活对象使内存紧凑,从而彻底消除碎片,但代价是要移动对象并更新所有引用,因此速度比不移动对象的标记-清除慢。",
"answer": true,
"explanation": "正确。Mark-Compact 在标记存活对象后,将它们紧凑到一端并更新所有指向它们的引用,消除碎片、有利于大对象连续分配。但压缩本身的移动量与引用更新会产生额外开销,所以速度慢于不做移动的 Mark-Sweep。正因如此,压缩算法常用于存活率较高的老年代。",
"source": null,
"related": []
},
{
"id": "tf-007",
"type": "true_false",
"difficulty": 3,
"tags": ["gc", "分代", "minor-gc", "eden"],
"question": "判断以下陈述是否正确:分代收集器中,当年轻代的 Eden 区被填满时会触发 Minor GC,而这类针对年轻代的 Minor GC 通常是一个需要停顿(stop-the-world)的事件。",
"answer": true,
"explanation": "正确。分代 GC 会把新建对象优先分配进 Eden,Eden 满时触发 Minor GC,把仍存活的对象复制到 Survivor 区,超龄后再升入老年代。传统多数实现中,Minor GC 通常是一个 stop-the-world 事件(即使现代收集器如 G1 也会产生暂停),在这段时间内应用线程会被暂停。",
"source": null,
"related": []
},
{
"id": "tf-008",
"type": "true_false",
"difficulty": 3,
"tags": ["gc", "G1", "默认收集器", "region"],
"question": "判断以下陈述是否正确:G1(Garbage-First)自 JDK 8 起就成为 HotSpot 的默认收集器,并把堆划分为多个相同大小的 Region。",
"answer": false,
"explanation": "错误。G1 确实基于 Region 并把堆划分为若干相同大小的 Region,但它直到 JDK 9 才成为 HotSpot 的默认收集器;JDK 8 默认的仍是 Parallel 组合。因此“自 JDK 8 起即是默认”的说法不成立。G1 同时支持通过 -XX:MaxGCPauseMillis 设置可预测的停顿时间目标。",
"source": null,
"related": []
},
{
"id": "tf-009",
"type": "true_false",
"difficulty": 4,
"tags": ["gc", "CMS", "碎片", "concurrent-mode-failure"],
"question": "判断以下陈述是否正确:CMS 采用标记-清除算法因此不会产生内存碎片,也正因如此它不会出现 Concurrent Mode Failure 问题。",
"answer": false,
"explanation": "错误。CMS 正是基于 Mark-Sweep 的收集器,因此会保留内存碎片(碎片过多时后续 Full GC 需要额外的空间整理);同时,当并发标记阶段老年代空间被耗尽时,CMS 会降级回退到 Serial Old 的全量停顿 GC,这称为 Concurrent Mode Failure。因此两个说法都不成立。",
"source": null,
"related": []
},
{
"id": "tf-010",
"type": "true_false",
"difficulty": 5,
"tags": ["gc", "三色标记", "漏标", "GC-Root"],
"question": "判断以下陈述是否正确:在三色标记法中,“漏标”的危害大于“多标”——漏标可能把存活对象误当作死对象回收,从而引发程序崩溃;同时,只有静态变量、JNI 全局引用等根对象出发的可达对象才由 GC Roots 判定存活,而堆中普通对象之间的引用并不是 GC Roots。",
"answer": true,
"explanation": "正确。三色标记把对象分为白/灰/黑三类:白色表示尚未被扫描、可回收;黑色表示已扫描且其所有子对象都处理完毕、安全存活。若因并发或写屏障问题造成漏标,使存活对象仍保持白色,就会在清扫阶段被错误回收,导致程序崩溃,因此漏标比多标更危险(漏标会误回收活对象,而多标至多保留垃圾,不会破坏程序)。而 GC Roots 是堆外能直达堆的出发点,包括静态字段引用、JVM 栈帧(局部变量)持有的对象、JNI 全局引用等;堆中普通对象之间的引用只是对象图的一条边,本身不是 GC Roots。本题两个子命题均正确,故整体正确。",
"source": null,
"related": []
}
]
}