2016-11-12 63 views
1

我正在研究一個應用程序,其目的是儘可能快地計算報表。如何找到哪個終結器耗時

我的應用程序使用了大量的內存;超過100 Go。

自我們上次發佈以來,我注意到一個很大的性能放緩。我的調查顯示,在計算過程中,我在40到60秒之間得到了很多垃圾回收! (JMC告訴我,他們是SerialOld,但我不知道它究竟意味着),當然,當JVM的垃圾收集,應用是絕對凍結

我現在調查這些垃圾收集的來源......這是一項非常艱苦的工作。

我懷疑,如果這些垃圾收集都這麼久了,那是因爲他們在finalize功能花費很多次(我知道,所有的庫中,我們整合來自其他球隊,他們中的一些使用終結)

但是,我不知道如何對這個假設進行確認(或不確定)如何找到哪個終結器是耗時的。

我找了一個很好的工具,甚至是一個很好的方法

這裏通過JVisualVM Taken from JVisualVM's "Tracer" tab

收集的數據正如你所看到的,我總是有很多「待終結」時,我有a 日誌舊垃圾

令人驚訝的是,當我使用JVisualVM時,上面的圖 定期從右向左滾動。當舊垃圾 觸發時,滾動停止(直到這裏,它看起來很正常,這是 世界末日)。然而,當突然滾動重新啓動,它 不是從舊垃圾的結束,而是從待定串行年底

這讓我覺得終結阻礙着JVM

有沒有人有一個交代這個?

非常感謝您 菲利普

+2

'finalize'方法在垃圾回收期間不執行。 – apangin

+0

當然?即使對於「SerializeOld」垃圾收集? 感謝您的回答 –

+2

絕對。沒有Java代碼在非併發GC階段運行。僅GC *發現*可終結對象並將它們添加到隊列中。該隊列稍後由['Finalizer']處理(http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/8b04ee324a1a/src/share/classes/java/lang/ref/Finalizer.java# l186)與其他Java線程一起運行的Java線程。 – apangin

回答

1

這裏是我會做調查的終結理論。

  1. 使用您最喜愛的Java分析器啓動JVM。

  2. 讓它運行足夠長的時間以獲得完整的堆。

  3. 啓動分析器。

  4. 觸發垃圾回收。

  5. 停止分析器。

現在你可以使用剖析信息來找出哪些(如果有的話)finalize方法是使用大量的時間。


不過,我懷疑,真正的問題將是一個內存泄漏,並且您的JVM越來越到堆與unreclaimable物體填滿點。這可以解釋頻繁的「SerialOld」垃圾收集。

或者,這可能只是一個大堆問題。 100Gb是...大。

2

我的應用程序使用了大量的內存;超過100 Go。

JMC告訴我,他們是SerialOld,但我不知道它究竟意味着

如果您正在使用串行收集了100GB堆那麼長時間的停頓是可以預料的,因爲串行收集器單線程和一個內核只能在單位時間內通過如此多的內存。

簡單地選擇任何一個多線程收集器應該產生較低的暫停時間。

但是,我不知道如何對這個假設進行確認(或不確定)如何找到哪個終結器是耗時的。

一般:收集更多的數據。對於與GC相關的事情,您需要啓用GC日誌記錄,在Java代碼(無論是您的應用程序還是第三方庫)中花費的時間,您需要一個分析器。

+0

僅供參考,我正在使用G1GC垃圾回收器 –

+0

「如果您使用的是串行收集器」1)您是什麼意思的串行收集器? 2)你的意思是我可以使用另一個嗎?怎麼樣? –

+1

你的問題說* SerialOld *,這是與G1GC互斥。 *如何?*堆棧溢出覆蓋還有很多其他答案,oracle的垃圾收集器文檔也是如此。 – the8472