2011-07-26 23 views
4

這些事情顯然需要仔細檢查並提供代碼才能徹底分析並提供良好的建議。儘管如此,這並不總是可行的,我希望可以根據我在下面提供的信息向我提供好的建議。Java內存使用情況/線程池性能問題

我有一個服務器應用程序,它使用偵聽器線程來偵聽傳入數據。傳入的數據被解釋爲應用程序特定的消息,然後這些消息引發事件。

到目前爲止,我並不完全控制事情的完成。因爲這是一個遺留應用程序,所以這些事件以前由同一個偵聽器線程(主要是單線程應用程序)負責處理。這些事件被髮送到一個黑盒子,並出現應寫入磁盤的結果。

爲了提高吞吐量,我想使用線程池來處理事件。這個想法是,偵聽器線程可以在每次創建事件時產生新的任務,並且線程將負責黑箱調用。最後,我有一個後臺線程執行寫入磁盤。

使用前面的設置和背景編寫器,一切正常,吞吐量比以前高1.6倍。

當我添加線程池但性能下降。一開始,一切似乎都能順利運行,但過了一段時間後,一切都非常緩慢,最終我得到了OutOfMemoryExceptions。奇怪的是,當我每次將任務添加到池時打印活動線程的數量(以及關於有多少任務排隊等信息),看起來好像線程池沒有問題跟上生產者(監聽器線程)。

使用top -H檢查CPU使用情況,它在開始的時候非常均勻地展開,但最後工作線程幾乎不活動,只有偵聽線程處於活動狀態。但它似乎並沒有提交更多的任務...

任何人都可以推測這些症狀的原因嗎?您認爲在添加多個線程時遺留代碼中有什麼東西(我無法控制)更糟糕嗎?內存不足的問題應該是因爲某個隊列變得太大,但由於線程池幾乎從不包含排隊的任務,所以不可能是這樣。

歡迎任何想法。特別是如何更有效地診斷這種情況的想法。我怎樣才能更好地瞭解我的線程正在做什麼等。

謝謝。

+0

黑盒是終端組件還是連接?它是被動的還是積極的組件?你從哪裏得到線程池? – alphazero

+0

請在黑匣子上提供更多詳情。 – toto2

+0

黑盒子只是一個內部函數,它接受A類型的對象並執行它們的各種操作以產生B類型的對象。這是應用程序的計算部分以及池中的線程執行的內容。線程池是標準的oracle/sun jdk實現。 – UmaN

回答

4

謝謝你的答案。我閱讀了Java VisualVM並將其用作工具。結果和結論在下面詳述。希望這些圖片能夠工作足夠長的時間。

我首先運行程序並創建了一些堆轉儲,以爲我可以分析轉儲並查看佔用了所有內存的內容。這可能會起作用,除非轉儲文件變得非常大,而我的工作站在嘗試訪問它時使用有限。在等待兩個小時進行一次手術後,我意識到我無法做到這一點。

所以我的下一個選擇是我,愚蠢,沒有想過。我可以減少發送給應用程序的消息數量,而增加內存使用量的趨勢應該仍然存在。此外,轉儲文件將更小,更快速地進行分析。

事實證明,當以較慢的速率發送消息時,不會發生內存不足問題!內存使用情況圖如下所示。

slow send http://img197.imageshack.us/img197/1628/slowsend.png

峯是累積的內存分配的結果和隨後的垃圾收集器運行後的低谷。雖然內存使用量肯定是相當驚人的,並且可能存在問題,但沒有觀察到長期的內存泄漏趨勢。

我開始逐步增加每秒發送的消息的比率,以查看應用程序撞擊牆的位置。下面的圖片顯示了與前一個非常不同的場景......

fast send http://img200.imageshack.us/img200/151/fastsend.png

因爲這種情況發生時發送的郵件的速度增加,我的猜測是,我釋放了監聽線程導致它能夠非常迅速地接受了不少的消息,這導致越來越多分配。垃圾收集器不會運行,並且內存使用量會觸發一堵牆。

當然,這個問題還有更多的問題,但是給了我今天發現的東西,我有一個相當不錯的主意,從這裏走到哪裏。當然,歡迎任何其他建議/意見。

這個問題可能應該被重新歸類爲處理內存使用情況而不是線程池......線程池根本就不是問題。

+0

+1這樣的詳細跟進..與圖表! – RHSeeger

5

減速然後內存不足意味着內存泄漏。

因此,我會先使用一些Java內存分析器工具來確定是否存在泄漏以及泄漏的內容。有時候你很幸運,泄露的對象是衆所周知的,而且很明顯是誰掛在他們不應該做的事情上。

1

正如djna所提到的,這可能是某種類型的內存泄漏。我的猜測是,你保持一個參考大概在他的要求:

  • 在調度線程真實排隊請求
  • 在與請求處理
  • 黑匣子這就是線程處理請求
  • 在寫入磁盤的寫入器線程中。

既然你說所有工作都在將線程池添加到混合之前找到,那麼我猜測池中的線程會在某處保留對請求的引用。這個想法是,沒有線程池,你不會重複使用線程,這樣信息就會消失。

按照djna的建議,您可以使用Java內存分析器來幫助確定數據堆疊的位置。

2

我同意@djna。 Java併發包的線程池工作。它不創建線程,如果它不需要它們。您會看到線程數量與預期的一致。這意味着可能遺留代碼中的某些內容尚未準備好進行多線程處理。例如一些代碼片段不同步。因此某些元素不會從集合中刪除。或者一些額外的元素存儲在集合中。所以,內存使用量正在增長。

順便說一句我不明白應用程序的哪一部分現在使用線程池。你有沒有一個處理事件的線程,現在你有幾個線程可以處理這個事件?你可能改變了線程間通信機制嗎?已添加隊列?這可能是您調查的另一個方向。

祝你好運!