cms 的并发清除阶段(concurrent marking)负责标记所有存活的对象,以便后续回收未标记的对象。它通过遍历 gc roots 和已标记对象的引用链来构建存活集合,期间允许用户线程继续运行,从而减少停顿时间。

CMS 垃圾回收器中并发清除的具体作用是什么
并发清除是 CMS 收集器的核心步骤之一,其主要作用是识别并标记堆内存中所有仍然被引用的存活对象。在初始标记阶段短暂停顿后,JVM 启动一个与用户线程并发执行的线程,从 GC Roots 开始深度优先搜索对象图。任何可达的对象都会被标记为“存活”,而未被标记的对象则被视为垃圾,等待后续的清理阶段进行物理删除。这一过程不阻塞应用线程,显著提升了用户体验。

import java.lang.ref.WeakReference;
public class CMSSimulation {
public static void main(String[] args) {
// 模拟创建大量对象
Object[] objects = new Object[1000];
for (int i = 0; i < 1000; i++) {
objects[i] = new byte[1024 * 10]; // 10KB
}
// 保留部分对象作为“存活”引用
WeakReference<Object> weakRef = new WeakReference<>(objects[500]);
// 触发垃圾回收
System.gc();
// 检查弱引用是否被清除
System.out.println("Weak Reference is cleared: " + weakRef.get() == null);
}
}并发清除阶段如何处理并发修改导致的漏标问题
在并发清除过程中,用户线程可能会同时分配新对象或修改引用关系,这可能导致某些本应存活的对象被遗漏标记。为了解决这个问题,CMS 使用了“增量更新”或“快照隔离”机制。具体来说,当用户线程修改引用时,JVM 会记录这些变化到一个日志结构中。在后续的重新标记阶段(Remark),JVM 会遍历这些日志,确保所有因并发修改而可能漏标的对象都被正确标记。这种机制虽然增加了额外的开销,但保证了标记的准确性。
立即学习“Java免费学习笔记(深入)”;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class ConcurrentMarkingExample {
private final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();
private final AtomicInteger markCount = new AtomicInteger(0);
public void addObject(String key, Object value) {
cache.put(key, value);
markCount.incrementAndGet();
}
public boolean isMarked(String key) {
return cache.containsKey(key);
}
public int getMarkCount() {
return markCount.get();
}
public static void main(String[] args) {
ConcurrentMarkingExample example = new ConcurrentMarkingExample();
// 模拟并发添加对象
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
example.addObject("key-" + i, new Object());
}
});
Thread t2 = new Thread(() -> {
for (int i = 100; i < 200; i++) {
example.addObject("key-" + i, new Object());
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Total marked objects: " + example.getMarkCount());
}
}基于程序中某个输入、条件或结果的具体问题
在上述代码示例中,如果我们在并发清除阶段手动触发 System.gc(),会发生什么?实际上,System.gc() 只是建议 JVM 执行垃圾回收,具体行为取决于 JVM 的配置和当前状态。在 CMS 模式下,它会触发完整的 CMS 流程,包括初始标记、并发清除、重新标记和并发清理。因此,手动调用 System.gc() 不会导致程序立即停止,而是由 JVM 异步处理。需要注意的是,频繁调用 System.gc() 可能会导致性能下降,因为每次 GC 都会消耗 CPU 资源。


















