当线程中的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循环运行很长时间,那么应用程序将耗尽内存并崩溃。
我的问题:这是真的吗?如果是这样,该怎么做才能避免呢?
答案 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。