GC回收对象真的至少标记对象两次吗

weixin_37970681 2018-01-17 12:42:41
   “要宣布一个对象死亡至少要经历两次标记过程:如果通过可达性分析没有与GC Roots相连接的引用链,会被第一次标记和进行一次筛选。筛选条件是此  对象是否有执行finalize()方法,当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过。虚拟机将这两种情况都视为“没有必要执行”。
    如果一个对象有必要执行finalize()方法,会被放在F-Queue队列,并在稍后一个由虚拟机自己建立的、低优先级的Finalizer线程去执行它,虚拟机会触  发这个方法,但是不会等它执行完,否则如果一个对象在finalize()方法中执行缓慢,那么内存回收系统会崩溃。finalize()方法是对象最后一次逃脱死亡机   会。稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象在第二次标记前没能拯救自己就要被回收。拯救办法是只要与引用链上任何一个对象建  立关联即可。”

上面的内容来自书籍,如果按照上述,那么当对象的finalize()方法没有必要执行,那不是只标记一次就可以吗?
...全文
2059 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_34035014 2020-12-28
  • 打赏
  • 举报
回复
引用 6 楼 鸾林居士 的回复:
在Java中每个对象都有一个唯一的“计数”,用来标记其被引用的次数:如果被变量引用则加一,否则减一;如果为0就表明该变量要被GC回收了
骗回复的吧 哈哈
架构帅 2020-12-25
  • 打赏
  • 举报
回复
引用 8 楼 鸾林居士 的回复:
[quote=引用 7 楼 bihanren32 的回复:] [quote=引用 6 楼 abc_12366 的回复:] 在Java中每个对象都有一个唯一的“计数”,用来标记其被引用的次数:如果被变量引用则加一,否则减一;如果为0就表明该变量要被GC回收了
瞎扯。。。。[/quote] 没工夫和你闲扯,你说别人总得有依据吧![/quote]确实瞎扯,他说的这是引用计数法,Java根本没用好吧
  • 打赏
  • 举报
回复
有一个问题:和 F-Queue 队列里面的对象保持连接的是属于可触及的还是不可触及的呢?如果是可触及的,楼上的分析就不对。可触及不会被清除,属性a 就会一直存在。。(关于这个问题没百度到,可能有点傻逼,才开始学JVM)
CLthinking 2019-01-19
  • 打赏
  • 举报
回复
我也是刚刚看到这里,有点疑惑上网搜到了这个帖子。 楼主,我说一下我的理解,你的分析没错,如果一个类没有重写finalize方法,貌似好像只需要标记一次就可以了;如果重写了finalize方法那么它可能在finalize方法内“拯救自己”。但是,如果这个“自我拯救”类含有其他没有重写finalize方法类的应用的时候会怎么样呢?这样只标记一次就清除的想法还是有些问题的。 比如下面代码:

public class FinalizeEscapeGC {
    class A {};
    private static FinalizeEscapeGC SAVE_HOOK = null;
    private A a = new A();
    public void isAlive() {
        System.out.println("yes! i'am still alive.");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize method executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable{
        SAVE_HOOK = new FinalizeEscapeGC();

        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if ( SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no, i'm dead!");
        }
    }
}
类FinalizeEscapeGC重写了finalize方法,类A没有重写finalize方法。当执行SAVE_HOOK = null后,这两个对象都不可达了,如果对类A的对象只标记一次就清除的话,那么类FinalizeEscapeGC在finalize方法“自我拯救”后的属性a就被清除了,就不在是原来的那个FinalizeEscapeGC了。
CuteXiaoKe 2018-05-29
  • 打赏
  • 举报
回复
个人的理解,至少两次标记过程: 1)第一次大标记:如果没有覆盖finalize()方法,就标记,等待第二次大标记,如果覆盖了,就进入F-Queue里面,并进行小规模标记 2)第二次大标记:F-Queue小规模标记完成后,对所有满足条件的(包括没有覆盖finalize()方法的和执行过finalize()的)对象加入“即将回收”的集合,并把第二次小规模标记的对象进行移除“即将回收”的集合的操作 - 至于“第二次小规模标记”是发生在第一次大标记和第二次大标记之间,其中的第二次是相对于第一次大标记,算不上是第二次标记,其实也是作者语义上的表述方式啦 - 为何没有覆盖finalize()方法的对象不再第一次大标记之后就立即释放,就是1楼说的那样,再次确认,顺便等待F-Queue的小规模标记以后再清理
  • 打赏
  • 举报
回复
我也感觉此处有矛盾。。
  • 打赏
  • 举报
回复
如果对象没有必要执行finalize()方法的话,标记一次就回收了
bihanren32 2018-03-15
  • 打赏
  • 举报
回复
引用 8 楼 abc_12366 的回复:
[quote=引用 7 楼 bihanren32 的回复:] [quote=引用 6 楼 abc_12366 的回复:] 在Java中每个对象都有一个唯一的“计数”,用来标记其被引用的次数:如果被变量引用则加一,否则减一;如果为0就表明该变量要被GC回收了
瞎扯。。。。[/quote] 没工夫和你闲扯,你说别人总得有依据吧![/quote] 还引用计数我问你 class A{ public Object o; } A a1 = new A(); A a2 = new A(); a1.o = a2; a2.o = a1; 引用计数怎么给我回收了
Narcicuss 2018-02-11
  • 打赏
  • 举报
回复
我也是觉着很矛盾,要是死缓的对象没有覆盖finalize()方法的话,那是不是就标记一次就被回收了。楼主有理清吗?求教~~
bihanren32 2018-02-10
  • 打赏
  • 举报
回复
引用 6 楼 abc_12366 的回复:
在Java中每个对象都有一个唯一的“计数”,用来标记其被引用的次数:如果被变量引用则加一,否则减一;如果为0就表明该变量要被GC回收了
瞎扯。。。。
galiniur0u 2018-01-17
  • 打赏
  • 举报
回复
楼主要跟前面的那句话连在一起看哈,"即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡",人的前提就是这个死缓的对象要经历两次标记。
weixin_37970681 2018-01-17
  • 打赏
  • 举报
回复
我就是细读了,,才觉得书上的矛盾啊,他的第一句话就说了:GC前对象要至少进行两次标记,而我从它下述的话中,觉得是一次即可的额,就是和你说的一样,但是网上的笔记也是说至少两次,矛盾啊
galiniur0u 2018-01-17
  • 打赏
  • 举报
回复
楼主要细读,是具有finalize()的对象并且没有执行finalize()方法的才会被放入F-Queue中并进行第二次标记,至于哪些没有finalize()方法或者已经执行完这个方法还是需要被回收的只标记一次就可以回收了。
weixin_37970681 2018-01-17
  • 打赏
  • 举报
回复
可是不是说第二次进行帅选的是小规模标记吗,是在用户没有重写finalize()方法或者没有调用过finalize()方法的对象才会做第二次标记。。。。。还是有点不太懂
oyljerry 2018-01-17
  • 打赏
  • 举报
回复
两次中的第二次其实是为了再做一些确认,防止回收的时候,又被引用了等

50,526

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧