Java 对象释放与 finalize 方法

简介: 关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。

本文谈论的知识很浅显,只是我发现自己掌握的相关知识并不扎实,对细节并不清楚,遂将疑惑解开,并记录于此。

按惯例先上结论,对如下知识点已经清楚的选手可以省下看本文的时间了。

结论

  1. 对象的 finalize 方法不一定会被调用,即使是进程退出前。

  2. 发生 GC 时一个对象的内存是否释放取决于是否存在该对象的引用,如果该对象包含对象成员,那对象成员也遵循本条。

  3. 对象里包含的对象成员按声明顺序进行释放。

证明

假设有以下类定义:

class A {
   
    public A() {
   
        System.out.println("A()");
    }

    protected void finalize() {
   
        System.out.println("~A()");
    }

    B b;
}

class B {
   
    public B() {
   
        System.out.println("B()");
    }

    protected void finalize() {
   
        System.out.println("~B()");
    }
}

结论 1 证明

main 方法中有如下代码:

A a = new A();
B b = new B();
a.b = b;
a = null;

输出是什么呢?

A()
B()

与我想象中的有些不一样,我以为至少在进程退出前 A 类对象和 B 类对象都会被释放掉的。

我们明确一下 finalize 方法的调用时机,引用官方 API 文档的解释:

Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup.

也就是说,finalize 是在 JVM 执行 GC 的时候才会执行的,而很显然,在这个例子里 main 方法退出时并没有执行 GC,而 GC 是否执行以及其执行的时机并不是我们可以精确控制的,此即证明了结论 1

结论 2 证明

虽然我们不能精确控制 GC 的时机,但我们可以给 JVM 建议,比如我们在最后加个 System.gc() 建议 JVM 进行 GC。

A a = new A();
B b = new B();
a.b = b;
a = null;
System.gc();

现在输出变成了

A()
B()
~A()

可见 JVM 听从了我们的建议,执行了 GC,由于此时 A 类对象已经没有引用了,所以它被释放,而该对象的 B 类对象成员由于被局部变量 b 引用,此时不会释放。

而一个在 GC 时对象成员也会被释放的 A 类对象调用是怎么样的呢?

A a = new A();
a.b = new B();
a = null;
System.gc();

此时输出为

A()
B()
~B()
~A()

如上两段代码执行结果的对比证明了结论 2

另外需要说明的是,Runtime 类里有一个 runFinalizersOnExit 方法,可以让程序在退出时执行所有对象的未被自动调用 finalize 方法,即使该对象仍被引用。但是从官方文档可以看出,该方法已经废弃,不建议使用,引用官方 API 文档如下:

Deprecated. This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock.

Enable or disable finalization on exit; doing so specifies that the finalizers of all objects that have finalizers that have not yet been automatically invoked are to be run before the Java runtime exits. By default, finalization on exit is disabled.

而同样是 Runtime 类里的 runFinalization 方法则在调用后并没有看到明显的效果,即如果不发生 GC,那即使调用了 runFinalization 方法,已经待回收的对象的 finalize 方法依然没有被调用。

结论 3 证明

我们修改一下几个类的定义:

class A {
   
    public A() {
   
        System.out.println("A()");
    }

    protected void finalize() {
   
        System.out.println("~A()");
    }

    B b;    // line a
    C c;    // line b
}

class B {
   
    public B() {
   
        System.out.println("B()");
    }

    protected void finalize() {
   
        System.out.println("~B()");
    }
}

class C {
   
    public C() {
   
        System.out.println("C()");
    }

    protected void finalize() {
   
        System.out.println("~C()");
    }
}

现在在 main 方法里有如下调用:

A a = new A();
a.b = new B();
a.c = new C();
a = null;
System.gc();

输出是

A()
B()
C()
~B()
~C()
~A()

而如果我们互换一下 A 类声明带注释的 line a 与 line b 的位置,即变成

C c;    // line b
B b;    // line a

输出变成

A()
B()
C()
~C()
~B()
~A()

此即证明了结论 3

目录
相关文章
|
17天前
|
存储 弹性计算 人工智能
阿里云Alex Chen:普惠计算服务,助力企业创新
本文整理自阿里云弹性计算产品线、存储产品线产品负责人陈起鲲(Alex Chen)在2024云栖大会「弹性计算专场-普惠计算服务,助力企业创新」中的分享。在演讲中,他分享了阿里云弹性计算,如何帮助千行百业的客户在多样化的业务环境和不同的计算能力需求下,实现了成本降低和效率提升的实际案例。同时,基于全面升级的CIPU2.0技术,弹性计算全线产品的性能、稳定性等关键指标得到了全面升级。此外,他还宣布了弹性计算包括:通用计算、加速计算和容器计算的全新产品家族,旨在加速AI与云计算的融合,推动客户的业务创新。
|
24天前
|
存储 人工智能 弹性计算
产品技术能力飞跃,阿里云E-HPC荣获“CCF 产品创新奖”!
9月24日,在中国计算机学会举办的“2024 CCF 全国高性能计算学术年会”中,阿里云弹性高性能计算(E-HPC)荣获「 CCF HPC China 2024 产品创新奖」。这也是继 2022 年之后,阿里云E-HPC 再次荣获此奖项,代表着阿里云在云超算领域的持续创新结果,其产品能力和技术成果得到了业界的一致认可。
|
8天前
|
SQL 人工智能 安全
【灵码助力安全1】——利用通义灵码辅助快速代码审计的最佳实践
本文介绍了作者在数据安全比赛中遇到的一个开源框架的代码审计过程。作者使用了多种工具,特别是“通义灵码”,帮助发现了多个高危漏洞,包括路径遍历、文件上传、目录删除、SQL注入和XSS漏洞。文章详细描述了如何利用这些工具进行漏洞定位和验证,并分享了使用“通义灵码”的心得和体验。最后,作者总结了AI在代码审计中的优势和不足,并展望了未来的发展方向。
|
3天前
|
负载均衡 算法 网络安全
阿里云WoSign SSL证书申请指南_沃通SSL技术文档
阿里云平台WoSign品牌SSL证书是由阿里云合作伙伴沃通CA提供,上线阿里云平台以来,成为阿里云平台热销的国产品牌证书产品,用户在阿里云平台https://www.aliyun.com/product/cas 可直接下单购买WoSign SSL证书,快捷部署到阿里云产品中。
1843 6
阿里云WoSign SSL证书申请指南_沃通SSL技术文档
|
2天前
|
存储 安全 Oracle
【灵码助力安全3】——利用通义灵码辅助智能合约漏洞检测的尝试
本文探讨了智能合约的安全性问题,特别是重入攻击、预言机操纵、整数溢出和时间戳依赖性等常见漏洞。文章通过实例详细分析了重入攻击的原理和防范措施,展示了如何利用通义灵码辅助检测和修复这些漏洞。此外,文章还介绍了最新的研究成果,如GPTScan工具,该工具通过结合大模型和静态分析技术,提高了智能合约漏洞检测的准确性和效率。最后,文章总结了灵码在智能合约安全领域的应用前景,指出尽管存在一些局限性,但其在检测和预防逻辑漏洞方面仍展现出巨大潜力。
|
6天前
|
Web App开发 算法 安全
什么是阿里云WoSign SSL证书?_沃通SSL技术文档
WoSign品牌SSL证书由阿里云平台SSL证书合作伙伴沃通CA提供,上线阿里云平台以来,成为阿里云平台热销的国产品牌证书产品。
1778 2
|
15天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
22天前
|
存储 人工智能 缓存
AI助理直击要害,从繁复中提炼精华——使用CDN加速访问OSS存储的图片
本案例介绍如何利用AI助理快速实现OSS存储的图片接入CDN,以加速图片访问。通过AI助理提炼关键操作步骤,避免在复杂文档中寻找解决方案。主要步骤包括开通CDN、添加加速域名、配置CNAME等。实测显示,接入CDN后图片加载时间显著缩短,验证了加速效果。此方法大幅提高了操作效率,降低了学习成本。
5075 15
|
9天前
|
人工智能 关系型数据库 Serverless
1024,致开发者们——希望和你一起用技术人独有的方式,庆祝你的主场
阿里云开发者社区推出“1024·云上见”程序员节专题活动,包括云上实操、开发者测评和征文三个分会场,提供14个实操活动、3个解决方案、3 个产品方案的测评及征文比赛,旨在帮助开发者提升技能、分享经验,共筑技术梦想。
1034 147
|
17天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1583 12