解释System.gc()的行为。

3
在《Java编程思想》一书中,作者提供了一种强制回收对象的技巧。我写了一个类似的程序来测试它(我的环境是Open JDK 7):
//forcing the garbage collector to call the finalize method
class PrintMessage
{
    private String message;

    public PrintMessage (String m)
    {
        this.message = m;
    }

    public String getMessage()
    {
        return this.message;
    }

    protected void finalize()
    {
        if(this.message == ":P")
        {
            System.out.println("Error. Message is: " + this.message);
        }
    }
}

public class ForcingFinalize
{
    public static void main(String[] args)
    {
        System.out.println((new PrintMessage(":P")).getMessage());
        System.gc();
    }
}

我认为关键是创建一个新的对象引用而不是赋值:new PrintMessage();

以下是让我感到困惑的地方。当我编译并运行此程序时,我得到了以下预期输出:

:P
Error. Message is: :P

然而,如果我将主函数的第一行修改为以下内容:
(new PrintMessage(":P")).getMessage();

我没有看到任何输出。为什么只有当我将输出发送到标准输出时,System.gc()才调用垃圾收集器?这是否意味着JVM只有在看到某些“真正”的用途时才创建对象?

1个回答

4

对象将被创建,字节码编译器不会优化掉它。在第二种情况下,您的程序在输出实际刷新到终端之前就退出了(或者甚至在运行终结器之前,您永远不知道GC和终结器实际发生的时间)。如果在System.gc()调用后添加Thread.sleep(),则会看到输出。


1
如果您在循环中调用此代码,编译器最终可能会将其优化掉。 - the8472
确实,它可能被JIT优化掉了。我指的是字节码编译器,我会澄清的。 - K Erlandsson
@KristofferE 好的,在添加了 Thread.sleep() 后它可以工作了。 :-) - ankush981

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接