GC(3)、Java对象回收概述

作者: 编程界的小学生 | 来源:发表于2017-09-05 15:08 被阅读47次

一、被可达性分析或者引用计数法标记为无用对象后就一定会被GC回收掉吗?

二、答案(纯文字,希望大家好好读,通俗易懂,很关键)
当然不是!!!!
一个对象的死亡至少要经历两次标记过程:
如果对象被标记为可回收对象,那他将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行回收”。(这也是为什么大家不鼓励重写finalize方法的原因之一)

如果对象被判定为有必要执行finalize()方法,那么这个对象会放到一个叫做F-Queue队列中,并在稍后一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它,这里的执行只是负责触发这个方法,并不一定等这个方法执行结束。这样做的原因是如果一个对象在finalize()方法中执行缓慢,或者发生了死循环,将很可能导致F-Queue队列中其他对象处于永久等待,甚至整个内存回收系统崩溃。

finalize()方法是对象逃脱死亡命运的最后你一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可(这里描述的是可达性分析算法,因为虚拟机几乎都不采取引用计数法)。譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在第二次标记时他将被移除出“即将回收”的队列;若对象这时候还没有逃脱,那么基本上真的就要被回收了。

三、用代码证明上面的答案

/**
 * 1、对象在被GC时候可以有一次自我挽救的机会
 * 2、这种自救的机会只有一次,因为一个对象的finalize方法最多只能被系统自动调用1次
 *
 * @author TongWei.Chen 2017-09-05 14:49:04
 */
public class FinalizeEscapeGC {

    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("我还活着呢....");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize方法执行了....");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

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

        //对象第一次成功拯救自己
        SAVE_HOOK = null;
        //督促垃圾收集器工作
        System.gc();

        //因为finalize方法优先级很低,所以暂停1s以等待它
        Thread.sleep(1000);
        if(SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("我已经死了....");
        }

        //下面这段代码与上面的完全相同,但是这次自救却失败了。

        //对象第二次成功拯救自己
        SAVE_HOOK = null;
        System.gc();

        //因为finalize方法优先级很低,所以暂停1s以等待它
        Thread.sleep(1000);
        if(SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("我已经死了....");
        }
    }
}

结果

finalize方法执行了....
我还活着呢....
我已经死了....

四、回收方法区
GC回收的不只是堆内存,还有方法区!!!
永久代(方法区)的垃圾收集主要回收两部分内容:废弃常量和无用的类。

判定一个常量是否是“废弃常量”很简单:
比如

String str = "abc";

abc在常量池中,但是现在str = null;不在引用abc这个常量了,那么这是发生内存回收的话,就会把abc清除常量池。

判定一个是否是“无用的类”很麻烦:

1、该类所有的对象都已经回收,也就是Java堆中不存在该类的任何对象。
2、加载该类的ClassLoader已经被回收。
3、该类对应的Class对象没有在任何地方被引用,无法再任何地方通过反射访问该类的方法。

若有兴趣,欢迎来加入群,【Java初学者学习交流群】:458430385,此群有Java开发人员、UI设计人员和前端工程师。有问必答,共同探讨学习,一起进步!
欢迎关注我的微信公众号【Java码农社区】,会定时推送各种干货:


qrcode_for_gh_577b64e73701_258.jpg

相关文章

  • GC(3)、Java对象回收概述

    一、被可达性分析或者引用计数法标记为无用对象后就一定会被GC回收掉吗? 二、答案(纯文字,希望大家好好读,通俗易懂...

  • LeakCanary源码分析

    LeakCanary原理概述: 在Java中,一个对象不再被任何GC roots引用,那么虚拟机在gc时就会被回收...

  • Android 内存泄漏分析和案例讲解

    一、概述 1. Java GC 的概念 GC 即为 Garbage Collection,垃圾回收机制。 Java...

  • 七年开发经验详解JVM的GC 算法

    概述 GC 是 JVM 自带的功能,它能够自动回收对象,清理内存,这是 Java 语言的一大优势,但是GC绝不仅伴...

  • 第三章(一)GC入门

    本篇主要讲述 JAVA与GC 、JAVA与引用 和JAVA对象回收流程 。 垃圾回收(Garbage Collec...

  • JVM之内存回收算法

    概述 GC需要完成3件事情: 那些内粗需要回收 什么时候回收 如何回收 那么该如何判断对象已死,可以被回收呢? 引...

  • Java 内存和垃圾回收

    概述 Java GC机制概括的说就是:该机制对JVM中的对象进行标记,并确定哪些内存需要回收,根据一定的回收策略,...

  • 深入学习java笔记-2.垃圾回收机制

    1.C++对比Java C++ 自己生成对象自己回收。(食堂)Java 生成的对象会有专门的GC回收。(饭店) 2...

  • 内存泄露案例

    对象本应被GC回收的情况,由于被外部对象引用持有,导致不能被正常回收 Bean.java MainActivity...

  • 【JVM篇】【垃圾回收机制】

    【JAVA】【JVM篇】【垃圾回收机制】 1. 概述: 垃圾收集GC(Garbage Collection)是Ja...

网友评论

本文标题:GC(3)、Java对象回收概述

本文链接:https://www.haomeiwen.com/subject/tuvujxtx.html