CMS 垃圾收集器垃圾收集大概分为 4 个阶段:
( 1 )初始标记
( 2 )并发标记预清除
( 3 )重新标记
( 4 )并发清除
在 ( 2 )并发标记预清除阶段,因为还有用户线程在进行,可能会有对象引用的更改, 所以需要( 3 )重新标记 重新修正存活对象
那么在( 4 )并发清除阶段(也是有用户线程在进行), 清除的时候,如果用户线程更改了对象的引用,导致原先一个应该不算存活的对象存活了 那么清除又将该对象清除了怎么办?
网上看了很多答案,没有说的很清楚,都是扯到了浮动垃圾上,浮动垃圾应该算是新产生的对象吧,也不会被清除,就是因为不被清除,才可能导致新的 GC
也看了《深入理解 Java 虚拟机》也没有一个很好的解释。
希望理解的朋友可以解答下
1
btnokami 2020-03-08 05:29:05 +08:00 via iPhone
想象力有限,楼主能举个已经丢失引用的对象被再次引用的例子吗
|
2
linwu OP public static void main(String[] args) {
A a = new A(); a.b = new B(); C c = new C(); c.b = a.b; a = null; } class A { ... } class A { ... } class A { ... } |
3
linwu OP class A {
B b; ... } class C { B b; ... } class B { ... } |
4
linwu OP 好像不行哈哈,那书上说的"标记期间应用可能被正在运行并更新引用"是什么意思呢?弄不懂
|
5
btnokami 2020-03-08 07:20:24 +08:00
@linwu 这个更新引用并不是指失去引用的对象被重新引用吧,而是指在运行期间这个对象有了新的引用,这样在做 tri-color marking 的时候颜色可能会被修改。
|
6
yafoo 2020-03-08 07:46:23 +08:00 via Android 1
以为你专门收集整理过时的 cms 系统呢
|
7
sagaxu 2020-03-08 09:40:48 +08:00 via Android
几年前 cms 就被废弃了,怎么还有人考古?
|
8
Jacky23333 2020-03-08 10:34:47 +08:00 via Android
@sagaxu 面试要问
|
10
liuming 2020-03-08 11:22:27 +08:00
"标记期间应用可能被正在运行并更新引用"指的是在初始标记时还存活但到重新标记时成垃圾了的情况吧
|
11
sagaxu 2020-03-08 11:51:25 +08:00 via Android 1
@bbao 2015 年提出废弃 cms,2017 年 Java 9 默认 g1,cms 则被标记为废弃。2019 年提出要删除 cms 相关代码,下下周将要发布的 Java 14 不再包含 cms 相关代码,从此用不了 cms。
@Jacky23333 有些面试还喜欢问 Java 7 和 Java 8 的 map 实现有什么不同。这种喜欢考古和面试专用 100 问的面试,反而简单,不用动脑,背宝典可破。 |
13
rrfeng 2020-03-08 14:53:54 +08:00 via Android
CMS 有一个 stw ( stop the world )阶段,意思是啥都不干只进行垃圾收集的。
|
15
Jacky23333 2020-03-08 15:17:26 +08:00 via Android
如果一个对象被判定为死亡,也就是不可达的,那你还能通过什么办法去更改到这个对象的引用,也就是说 a = new Instance();a = null,那你还能够怎样去访问到 Instance()并更改它的引用呢。所以应该不会出现你所说的问题
|
16
bbao 2020-03-08 15:17:40 +08:00
@rrfeng 第一次初始标记和重新标记都是 STW,标记对象,并不进行垃圾收集。在预清理阶段会有 minor gc 的发生,减少重新标记时对象的数量和减少 stw 时间。
|
17
zrc 2020-03-08 15:23:08 +08:00
这些线程都是到了 safepoint 的时候才 stw 吧,可能和 safepoint 的定义点有关
|
18
gaius 2020-03-08 15:57:55 +08:00 via Android
再次标记是扫并发标记改变阶段改变的对象,我的理解是对象地址,如果不修正一下会因为地址错误清理不了,应该不会出现垃圾又被重新引用的情况吧?
|
19
optional 2020-03-08 16:08:05 +08:00
因为是并发标记,有些引用在 register 和 cpu cache 里吧
|
20
Goooogle 2020-03-08 17:10:49 +08:00
如何判断一个对象是否还在被引用?
JVM 会从栈帧、常量区、方法区、Native 区中的引用开始进行可达性分析,当一个对象不可达后,才能会标记为可回收,放入 finalize 队列,去执行 finalize 方法。当执行完 finalize 方法后(或许不会执行),如该对象还是不可达,那这个对象就真的无法再被代码访问到。(毕竟 Java 不能直接操作指针) 到于浮动垃圾,是指在进行可达性分析时,新生成了对象,或者是原有的可达对象在经过一段时间后引用引用状态变成不可达。 所以根本问题在于:当对象标记为不可达后,真的就不会再回来了 |