2009-09-25 45 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 ...)
  • 重新設計你的應用程序,使它不會創建數千個線程。 (線程池和某種工作隊列是一個可行的方法。)