Java线程垃圾收集

时间:2012-07-13 12:35:24

标签: java multithreading garbage-collection

当线程中的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循环运行很长时间,那么应用程序将耗尽内存并崩溃。

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

5 个答案:

答案 0 :(得分:7)

首先,在Java中GC是非确定性的。当不再引用该对象时,它适合在下一次GC运行中收集,但不是强制要求。即使致电System.gc(),也只是对GC系统的建议。

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

答案 1 :(得分:4)

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

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

您也可以显式触发GC或使用像visualvm这样的JMX工具。

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

答案 2 :(得分:1)

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

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

但是没有保证GC何时会收集它。这是GC特定的事情。

答案 3 :(得分:0)

它被授予它将在线程之后被调用,而不是完成作业并且不使用更多数据,但是不能用于,因为垃圾收集器会被虚拟机自动定期调用或者当某些事件发生时。

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

您也可以使用:System.gc()明确地称呼它。

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

答案 4 :(得分:0)

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

GC可以随时点击,正如其他人所说,运行线程(start() 启动的线程)只有在完成执行后才会被GC。