为什么在方法返回之前,方法中声明的对象会被垃圾收集? [英] Why an object declared in method is subject to garbage collection before the method returns?

查看:123
本文介绍了为什么在方法返回之前,方法中声明的对象会被垃圾收集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑在方法中声明的对象:

Consider an object declared in a method:

public void foo() {
    final Object obj = new Object();

    // A long run job that consumes tons of memory and 
    // triggers garbage collection
}

在 foo()返回之前,obj是否会受到垃圾收集的影响?

Will obj be subject to garbage collection before foo() returns?

UPDATE
之前我认为obj不受垃圾收集的影响,直到 foo()返回。

UPDATE: Previously I thought obj is not subject to garbage collection until foo() returns.

然而,今天我发现自己错了。

However, today I find myself wrong.

我花了几个小时来修复bug,最后发现问题是由obj垃圾收集引起的!

I have spend several hours in fixing a bug and finally found the problem is caused by obj garbage collected!

任何人都能解释为什么会这样吗?如果我想要obj固定如何实现它?

Can anyone explain why this happens? And if I want obj to be pinned how to achieve it?

这是有问题的代码。

public class Program
{
    public static void main(String[] args) throws Exception {
        String connectionString = "jdbc:mysql://<whatever>";

        // I find wrap is gc-ed somewhere
        SqlConnection wrap = new SqlConnection(connectionString); 

        Connection con = wrap.currentConnection();
        Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
             ResultSet.CONCUR_READ_ONLY);
        stmt.setFetchSize(Integer.MIN_VALUE);

        ResultSet rs = stmt.executeQuery("select instance_id, doc_id from
               crawler_archive.documents");

        while (rs.next()) {
            int instanceID = rs.getInt(1);
            int docID = rs.getInt(2);

            if (docID % 1000 == 0) {
                System.out.println(docID);
            }
        }

        rs.close();
        //wrap.close();
    }
}

运行Java程序后,它将打印以下内容崩溃之前的消息:

After running the Java program, it will print the following message before it crashes:

161000
161000
********************************
Finalizer CALLED!!
********************************
********************************
Close CALLED!!
********************************
162000
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: 

这里是类SqlConnection的代码:

And here is the code of class SqlConnection:

class SqlConnection
{
    private final String connectionString;
    private Connection connection;

    public SqlConnection(String connectionString) {
        this.connectionString = connectionString;
    }

    public synchronized Connection currentConnection() throws SQLException {
        if (this.connection == null || this.connection.isClosed()) {
            this.closeConnection();
            this.connection = DriverManager.getConnection(connectionString);
        }
        return this.connection;
    }

    protected void finalize() throws Throwable {
        try {
            System.out.println("********************************");
            System.out.println("Finalizer CALLED!!");
            System.out.println("********************************");
            this.close();
        } finally {
            super.finalize();
        }
    }

    public void close() {
        System.out.println("********************************");
        System.out.println("Close CALLED!!");
        System.out.println("********************************");
        this.closeConnection();
    }

    protected void closeConnection() {
        if (this.connection != null) {
            try {
                connection.close();
            } catch (Throwable e) {
            } finally {
                this.connection = null;
            }
        }
    }
}


推荐答案

由于您的代码已编写,wrap指向的对象不应该有资格进行垃圾回收,直到wrap在堆栈结束时弹出堆栈。方法。

As your code is written the object pointed to by "wrap" shouldn't be eligible for garbage collection until "wrap" pops off the stack at the end of the method.

收集它的事实告诉我你的代码编译后的与原始来源不匹配,编译器有做了一些优化,比如改变这个:

The fact that it is being collected suggests to me your code as compiled doesn't match the original source and that the compiler has done some optimisation such as changing this:

SqlConnection wrap = new SqlConnection(connectionString); 
Connection con = wrap.currentConnection();

到此:

Connection con = new SqlConnection(connectionString).currentConnection();

(甚至内联整个事情)因为在这一点之外没有使用换行。创建的匿名对象将立即符合GC的条件。

(Or even inlining the whole thing) because "wrap" isn't used beyond this point. The anonymous object created would be eligible for GC immediately.

唯一可靠的方法是反编译代码并查看已对其执行的操作。

The only way to be sure is to decompile the code and see what's been done to it.

这篇关于为什么在方法返回之前,方法中声明的对象会被垃圾收集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆