6

run()当线程内的方法完成或调用它的函数完成时,是否会收集线程垃圾?

我没有问题或任何东西,但我想避免内存泄漏等。

对于喜欢代码的人:

public void SomeClass {
    public SomeClass() {

    }

    public void someMethod() {
        Object data = veryBigObject;

        while(true) {
            MyThread thread = new MyThread(veryBigObject);
            thread.run();

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) { /* do nothing */ }
        }
    }

    public static void main(String[] args) {
        SomeClass myclass = SomeClass();
        myclass.someMethod();
    }
}


public class MyThread extends Thread {
    private Object data;

    public Thread(Object data) {
        this.data = data;
    }

    public void run() {
        // do stuff with data
    }
}

在我知道的所有语言中,当方法结束时会收集垃圾(如果该语言有的话)。我认为Java也是如此。这意味着理论上我创建的线程someMethod()直到someMethod()结束才会被收集。如果我们假设 while 循环运行很长时间,应用程序将耗尽内存并崩溃。

我的问题:这是真的吗?如果是这样,应该怎么做才能避免呢?

4

5 回答 5

7

首先,Java GC 是非确定性的。当对象不再被引用时,适合在下次 GC 运行时被收集,但不是强制的。甚至调用System.gc()只是对 GC 系统的一个建议。

其次,重要的是引用。在循环的每个实例中,您都会覆盖对线程对象的引用。如果线程已经完成,则无需退出方法来收集它们(当然,在线程运行时它们不会被收集,即使您的代码没有引用它)。退出创建对象的方法的问题不相关。

于 2012-07-13T12:40:31.687 回答
4

GC 在需要时运行(例如,当您尝试分配内存并且伊甸园空间已满时)

这可能发生在您分配内存的任何代码行(在任何线程中)这意味着即使您不在一个线程中分配内存,GC 仍然可能发生,因为内存是在另一个线程中分配的。

您还可以显式触发 GC 或使用诸如 visualvm 之类的 JMX 工具。

简而言之:GC 可以随时发生。

于 2012-07-13T12:40:24.650 回答
1

在另一个循环迭代开始后,MyThread 的每个实例都将被标记为由 GC 收集。如果您想将 MyThread 作为线程运行,您需要使用 start() 方法!

在您使用 start() 方法的情况下,MyThread 将在另一个循环迭代开始后立即被标记为由 GC 收集,并且!run() 方法的结束。

但是对于 GC 何时收集它并没有任何保证。这是 GC 特有的事情。

于 2012-07-13T12:53:39.283 回答
0

允许它在完成工作并且不使用更多数据之后在线程上被调用,但不是什么时候,因为垃圾收集器是由虚拟机定期自动调用或在某些事件发生时调用的。

因此,从线程终止且数据未使用时起,您无法知道数据是否已自动收集。

您也可以使用以下命令显式调用它:System.gc()

如果您的线程被终止并且他的指向数据没有被更多使用,那么在显式调用之后它被授予它已被收集。

于 2012-07-13T12:46:20.553 回答
0

在您上面发布的代码中,实际上没有并行执行线程。要生成一个新线程,您需要调用.start()内部调用.run()线程方法的方法。现在,一切都在按顺序运行。所以你的 thread.run() 将完成它的执行,你当前的线程将休眠,你while将继续它的循环并一遍又一遍地执行它。

GC 可以在任何时候命中,并且正如其他人所说,正在运行的线程(开始的线程start())只有在它们完成执行后才会被 GC。

于 2012-12-12T17:07:36.163 回答