我几天都遇到了这个内存泄漏问题,我想我现在有一些线索。我的 java进程的内存不断增长,但堆却没有增加。我被告知,如果我创建了很多线程,这是可能的,因为Java线程使用堆外部的内存。
我的java进程是服务器类型程序,因此有1000-2000个线程。正在创建和删除。如何回收java线程使用的内存?我是否只是擦除对线程对象的所有引用并确保终止它?
答案 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没有被垃圾收集。
任何仍处于活动状态的线程都不会被垃圾回收。线程处于活动状态,直到run
调用的Thread.start()
方法正常或通过抛出异常退出。一旦发生这种情况(并且线程的未捕获异常处理程序已经完成),该线程就已经死了。
对线程的Thread对象的任何实时引用都将阻止它被垃圾回收。实时引用可以在您的代码中,或者如果您使用线程池,它们可以是池数据结构的一部分。
我的java进程的内存不断增长,但堆却没有增加。
那是因为每个线程都有一个没有在Java堆中分配的大型(例如1Mb)堆栈段。
线程的堆栈段仅在线程启动时分配,并在线程终止后立即释放。这同样适用于(我认为)线程的线程局部映射。不是“活着”的Thread对象根本不会占用太多内存。
总结一下。你似乎有很多活的线程。只要它们还活着,它们就不会被垃圾收集,而让它们释放记忆的唯一方法就是让它们死掉......不知怎的。
要减少内存使用量,您需要执行以下一项或多项操作:
run()
方法等)以找出它们仍然存在的原因。 答案 3 :(得分:0)
这是很多线程,每个线程都会产生内存开销,以及管理它们的其他资源(上下文切换等)。使用分析器查看线程活动 - 您可能会发现大多数线程大多数时间都处于空闲状态。
我建议第一步是使用java.util.concurrent提供的线程池来管理线程。不是创建线程,而是创建传递给池的任务。调整池,直到您的线程数量少得多,保持相当繁忙。这可能很好地解决了内存问题;它肯定会提高性能。