java - writeObject(this) 停止程序

标签 java finalizer

我正在学习垃圾收集和 Java 对象序列化。在我包含序列化代码之前的代码中,有 3 个对象已完成。现在只有一个 Finalize() 被调用,并且在创建 FileOutputStream 对象后,我的程序正在停止

我已经在 Project 类中实现了 java.io.Serializable,之前当 Finalize() 只有一个 println 时,它执行得很完美,3 个对象正在最终确定,但现在它在该行之后停止

FileOutputStream fout = new FileOutputStream(projectName + ".bin");

类项目:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Project implements Serializable {

    private static final long serialVersionUID = 4721106266710903835L;
    int projectID;
    String projectName;

    public Project() {
        super();
    }

    public Project(int projectID, String projectName) {
        super();
        this.projectID = projectID;
        this.projectName = projectName;
        System.out.println("Object created : " + this.projectID);
    }

    @Override
    protected void finalize() {
        try {
            super.finalize();
        } catch (Throwable e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        System.out.println(this.projectID + " Deallocated");

        try {

            System.out.println("Test 0");
            FileOutputStream fout = new FileOutputStream(projectName + ".bin");
            System.out.println("Test 1");
            ObjectOutputStream oout = new ObjectOutputStream(fout);
            System.out.println("Test 2");

            oout.writeObject(this);
            oout.flush();
            System.out.println("Done");

            fout.close();
            oout.close();
        }
        catch(IOException e) {
            e.printStackTrace();
            System.out.println("Exception");
        }

    }

}

类项目控制:

public class ProjectControl {

    public static void main(String[] args) {
        Project p = new Project(100, "ABC");
        System.out.println(p.projectID);
        System.out.println(p.projectName);

        p = null;

        Project p1 = new Project(200, "DEF");
        Project p2 = p1;

        p1 = null;
        System.out.println(p2.projectID);

        p2 = new Project(300, "GHI");
        System.out.println(new Project(400, "GHI").projectID);
        System.gc();
    }
}

最初finalize()每次打印时运行3次

<<projectID>> deallocated

现在编程一次后就停止了。在遇到该行之前,仅测试 0 被打印一次

FileOutputStream fout = new FileOutputStream(projectName + ".bin");

最佳答案

很难说发生了什么,但我的猜测是,当调用对象的 finalize 方法时,JVM 正在退出。 (finalize() 调用将在守护进程终结器线程上运行。当 JVM 检测到所有非守护线程都已终止时,它会启动有序关闭过程。)

为了让您的方案可靠地工作,需要 100% 防炸弹保证您的 finalize 方法将在 JVM 退出之前完成。 JVM 不提供此类保证。相反javadoc对于 finalize() 说:

[T]here are no guarantees regarding the timing of finalization. The finalize method might be called on a finalizable object only after an indefinite delay, if at all.

JLS 12.6说:

The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.

如果您依靠终结来保存对象的状态,那么您的基础就非常不稳定。


曾经有一种名为java.lang.System.runFinalizersOnExit的方法,理论上可能会有所帮助。然而,它在 Java 1.2 中已被弃用,并在 Java 11 中被删除。根据 javadoc:

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.

因此,如果我们仅从表面上理解该警告,则该方法不会为您提供 100% 可靠的持久性,甚至可能导致更严重的问题。


finalize 方法和机制在 Java 9 中被标记为已弃用,并且可能会在未来的 Java 版本中删除。当这种情况发生时,对于任何依赖于最终确定的应用程序来说,这将是“道路的尽头”。您应该将此视为一个重大暗示,您应该重新考虑您的策略。


如果尽管我上面说了这么多,你仍然想要一种使用终结器“让它工作”的方法,我认为没有一个是可靠的。

关于java - writeObject(this) 停止程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57687870/

相关文章:

java - 对相互链接的连音列表进行排序

c# - 什么时候不能使用 SafeHandle 而不是 Finalizer/IDisposable?

c# - .NET - 终结器和退出(0)

c# - 访问托管内容的终结器

java - 为什么 finalize() 不会像 java 中的构造函数那样自动调用其父 finalize()?

java - 我们如何在Java中的方法之前调用 `@something`?

java - OpenGL : performance in C++ (NDK) vs Java (Dalvik) 中的 Android 专用游戏

.net - SqlConnection 会被 GC 处理掉吗?

java - 在应返回结果的 Javafx GUI 中使用线程

java - Spring Batch - 用于不同分隔文件的 FlatFileItemReader