如何回收Java线程堆栈使用的内存?

时间:2009-09-25 19:40:37

标签: java optimization memory memory-management memory-leaks

我几天都遇到了这个内存泄漏问题,我想我现在有一些线索。我的 java进程的内存不断增长,但堆却没有增加。我被告知,如果我创建了很多线程,这是可能的,因为Java线程使用堆外部的内存。

我的java进程是服务器类型程序,因此有1000-2000个线程。正在创建和删除。如何回收java线程使用的内存?我是否只是擦除对线程对象的所有引用并确保终止它?

4 个答案:

答案 0 :(得分:4)

是。这就是答案。只要存在对任何Java对象的活动引用,那么该对象在完成后将不会被垃圾回收。 如果你正在创建和销毁线程而不是汇集它们,我认为你还有其他问题。

答案 1 :(得分:1)

从Java API docs线程死亡时:

  

所有非守护程序线程的线程都已经死亡,无论是通过调用run方法返回还是抛出一个超出run方法传播的异常。

线程从 run()方法返回时会死亡。当他们死亡时,他们是垃圾收集的候选人。您应该确保线程释放对对象的所有引用并退出 run()方法。

我认为对你的线程的引用归零将不会真正起作用。

您还应该查看Java 5及更高版本中的新线程功能。检查API文档here中的包 java.util.concurrent

我还建议您查看书籍Concurrency in Practice。这对我来说是无价的。

答案 2 :(得分:1)

有两件事会导致Thread没有被垃圾收集。

  1. 任何仍处于活动状态的线程都不会被垃圾回收。线程处于活动状态,直到run调用的Thread.start()方法正常或通过抛出异常退出。一旦发生这种情况(并且线程的未捕获异常处理程序已经完成),该线程就已经死了。

  2. 对线程的Thread对象的任何实时引用都将阻止它被垃圾回收。实时引用可以在您的代码中,或者如果您使用线程池,它们可以是池数据结构的一部分。


  3.   

    我的java进程的内存不断增长,但堆却没有增加。

    那是因为每个线程都有一个没有在Java堆中分配的大型(例如1Mb)堆栈段。

    线程的堆栈段仅在线程启动时分配,并在线程终止后立即释放。这同样适用于(我认为)线程的线程局部映射。不是“活着”的Thread对象根本不会占用太多内存。


    总结一下。你似乎有很多活的线程。只要它们还活着,它们就不会被垃圾收集,而让它们释放记忆的唯一方法就是让它们死掉......不知怎的。

    要减少内存使用量,您需要执行以下一项或多项操作:

    • 查看线程代码(run()方法等)以找出它们仍然存在的原因。
    • 减小线程堆栈的大小。 (理论上,你可以低至64K ......)
    • 重新设计您的应用,以便它不会创建数千个线程。 (线程池和某种工作队列是一种可能的方法。)

答案 3 :(得分:0)

这是很多线程,每个线程都会产生内存开销,以及管理它们的其他资源(上下文切换等)。使用分析器查看线程活动 - 您可能会发现大多数线程大多数时间都处于空闲状态。

我建议第一步是使用java.util.concurrent提供的线程池来管理线程。不是创建线程,而是创建传递给池的任务。调整池,直到您的线程数量少得多,保持相当繁忙。这可能很好地解决了内存问题;它肯定会提高性能。