一个GCRoot不可达的对象,会立刻被垃圾回收吗?

image

这个问题是我在刷牛客面经的时候遇到的,还特地整理在了我的常规面试题文档中,所以这道题主要考察的就是finalize方法的影响。

java提供了一个finalize方法,可以帮助我们进行资源释放,类似于C++中的析构函数。但是目前普遍的认识是不要使用,为什么呢?就是因为对java虚拟机的垃圾回收有影响。这篇文章对其进行一个说明。

一、为什么有影响

我们都知道一个对象GCRoot不可达,java虚拟机就认为是垃圾对象,就会进行垃圾回收,但是如果这个对象包含了finalize函数,性质就不一样了。怎么不一样了呢?

java虚拟机在进行垃圾回收的时候,一看到这个对象类含有finalize函数,就把这个函数交给FinalizerThread处理,而包含了这个finalize的对象就会被添加到FinalizerThread的执行队列,并使用一个链表,把这些包含了finalize的对象串起来。

image

他的影响在于只要finalize没有执行,那么这些对象就会一直存在堆区,不过这里只是4个包含了finalize的对象,影响不是那么大,如果有一万个或者是十万个呢?这就影响大了。

finalize的原理其实很简单,在这里简要的梳理一下:

(1)对象在初始化的过程中会判断是否重写了finalize,方法是判断两个字段标志has_finalizer_flag和RegisterFinalizersAtInit。

(2)如果重写了finalize,那就把当前对象注册到FinalizerThread的ReferenceQueue队列中。注册之后的对象就叫做Finalizer。方法是调用register_finalizer函数。此时java虚拟机一看当前有这个对象的引用,于是就不进行垃圾回收了。

(3)对象开始被调用,FinalizerThread线程负责从ReferenceQueue队列中获取Finalizer对象。开始执行finalize方法,在执行之前,这个对象一直在堆中。

(4)对象执行完毕之后,将这个Finalizer对象从队列中移除,java虚拟机一看对象没有引用了,就进行垃圾回收了。

这就是整个过程。不过在这里我们主要看的是finalize方法对垃圾回收的影响,其实就是在第三步,也就是这个对象含有finalize,进入了队列但一直没有被调用的这段时间,会一直占用内存。

注意:这里其实就是一道面试题,我在看牛客网上的面经时,看到有人被问到过。也就是GCRoot不可达的对象,会立刻被垃圾回收吗?

我们使用一个案例来分析一波:

二、案例演示

我们创建一个类

public class TestFinalizer {
    public static class Fdd {
        //分配1M
        private byte[] content = new byte[1024*1024];
        @Override
        protected void finalize() {
            System.out.println("finalize被执行");
        }
    }
    public static void main(String[] args) {   
        for (int i = 0; i < 1000; i++) {
            Fdd fdd = new Fdd(); 
        }
    }
}

现在创建了类,我们设置一下参数。

# 最大堆内存
-Xmx5m 
# 最小堆内存
-Xms5m  
# 堆内存溢出错误打印
-XX:+HeapDumpOnOutOfMemoryError 
# 把堆相关信息保存在下列路径
-XX:HeapDumpPath=F:/a.dump

在main方法中,创建了1000个Fdd对象,如果不执行finalize方法,那么因为没有调用所以会进行垃圾回收,此时不断我们创建多少个,都不会出现任何问题。但是如果存在finalize方法,就不一样了。

java.lang.OutOfMemoryError: Java heap space
Dumping heap to F:/a.dump ...
finalize被执行
finalize被执行
finalize被执行
finalize被执行
finalize被执行
finalize被执行
finalize被执行
Unable to create F:/a.dump: File exists
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.fdd.chapter2.TestFinalizer$Fdd.<init>(TestFinalizer.java:6)
    at com.fdd.chapter2.TestFinalizer.main(TestFinalizer.java:14)

我们看到每个对象都会执行finalize,在执行之前的这段时间一直会在堆区,执行完了就会被清理,所以你看到这里执行了不少于5次的finalize方法。但是对象一旦超出了我们设置的5M,就会出现内存溢出。一句话总结就是出现了对象堆积。现在使用MAT工具来分析一下。

Mat工具是一个插件,也可以自己下载一个。下载完成之后打开我们刚刚生成的a.dump即可。

下面这张图就是分析的结果:

image

a这块的内容就是Finalizer,也就是我们的Fdd对象,b包含的比较多,乱七八糟的剩余信息。当然你也可以查看一些其他的信息。都在MAT工具上。还有一些正在执行的finalizer和准备执行的。

image

OK,一些其他的信息就不再展示了。

结论

一个GCRoot不可达的对象,不会立刻被垃圾回收,首先还会判断是否包含了finalize方法,如果有那就先执行finalize方法,如果这样的对象比较多,那么这部分对象及时GCRoot不可达,变得没用了,也会留在内存中,影响程序的效率。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容