【问题标题】:Java thread garbage collectionJava线程垃圾回收
【发布时间】:2012-07-13 12:35:24
【问题描述】:

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

我的问题:这是真的吗?如果有,如何避免?

【问题讨论】:

  • 在我知道的所有语言中,当方法结束时会收集垃圾(如果该语言有的话)。指出一种语言!您误认为带有自动引用计数的垃圾收集和类似 C++ 的堆栈分配对象的析构函数。 Java 不会在堆栈上分配任何对象(按设计,但技术上可以通过 EA [转义分析] 或 ED [转义检测]) 因此该语句充其量是不正确的(在最坏的情况下是非常错误的)跨度>

标签: java multithreading garbage-collection


【解决方案1】:

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

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

【讨论】:

  • 所以因为我正在覆盖引用,所以线程无法访问,因此在完成运行时会收集垃圾,是吗?
  • "当它完成运行时" 没有什么特别的事情发生,除非线程完成运行。 GC 可以随时运行。
【解决方案2】:

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

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

您还可以显式触发 GC 或使用 Visualvm 等 JMX 工具。

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

【讨论】:

  • 真正的并发 GC 可以随时运行,甚至可以一直运行(尽管后者需要读屏障)
【解决方案3】:

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

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

但没有保证 GC 何时收集它。这是 GC 特有的东西。

【讨论】:

    【解决方案4】:

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

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

    你也可以明确地调用它:System.gc()

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-09
        • 1970-01-01
        • 2011-01-26
        • 1970-01-01
        相关资源
        最近更新 更多