2009-09-25 47 views
2

我一直有这个内存泄漏问题几天,我想我现在有一些线索。我的java进程的内存不断增长,但堆不增加。我被告知,如果我创建多个线程,这是可能的,因为Java线程使用堆外的内存。如何回收Java线程堆栈使用的内存?

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

回答

4

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

+0

+1了联合提。 – 2009-09-25 19:58:08

1

从Java API文档线程死的时候:

所有线程都没有守护线程已经死亡,要么通过调用run方法返回或通过抛出一个传播超越了run方法异常。

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

我不认为你的线程的nulling引用真的会诀窍。

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

我也推荐你去看书Concurrency in Practice。这对我来说是无价的。

+1

“当它们死亡时,它们是垃圾收集的候选对象”,但前提是没有其他对象仍然持有对这些死亡线程的引用。 – 2009-09-25 20:33:39

+0

如果它们是守护线程呢? – erotsppa 2009-09-25 20:51:09

+0

@erotsppa:守护进程线程相同。 – 2009-09-26 03:17:45

0

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

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

1

有两件事情会导致线程不被垃圾收集。

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

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


我java进程不断增长,但尚未堆不增加的内存。

这将是因为每个线程都有一个大的(例如1Mb)堆栈段,它并未在Java堆中分配。

当线程启动线程的堆栈段只分配,并尽快线程终止释放。这同样适用于(我认为)线程的线程局部映射。一个非“活着”的线程对象根本不占用太多内存。


所以总结一下。您似乎有很多活动的线程。只要他们还活着,他们就不会被垃圾收集,而让他们释放记忆的唯一方法就是让他们死......不知何故。

为了减少内存使用,你需要做的一项或多项:

  • 看线程代码(run()方法等),以弄清楚他们为什么还在闲逛。
  • 减小线程堆栈的大小。 (理论上,你可以低至64K ...)
  • 重新设计你的应用程序,使它不会创建数千个线程。 (线程池和某种工作队列是一个可行的方法。)