
我在兩台不同的伺服器(oracle jdk7)上有兩個不同的 tomcat 7 實例,硬體配置幾乎相同(均 > 24 GB RAM)。兩台tomcat伺服器具有相同的配置,並且在這些伺服器上部署相同的網路應用程式。 Catalina 選擇如下:
-XX:PermSize=128m -XX:MaxPermSize=512M -Xmx2048m -XX:+CMSIncrementalMode -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC
執行負載測試時(透過大量並行執行的請求對 REST API 施加壓力),其中一個伺服器會拋出異常java.lang.OutOfMemoryError: Java heap space
(以下是堆疊追蹤:http://pastebin.com/wuS1MVCC),其他伺服器工作得很好。我不知道為什麼會發生這種情況。有人遇到類似的問題嗎?
答案1
因此,發生的情況是,您的 Tomcat JVM 之一試圖超過為其分配的 2048 MB 堆。
聽起來您正在尋找一個具體的答案以及要嘗試的事情清單,所以這裡是:
堆耗盡要么是由於記憶體洩漏(每個請求都會洩漏一點點),要么是在加載場景中,這可能是因為您向 JVM 拋出的資料超出了 JVM 的處理能力。您想要確定哪一個是問題所在,因此首先要查看如何產生負載。
如果問題僅出現在較高層級的平行請求上,而不會出現在較低層級上,那麼您遇到的問題是請求數乘以處理每個請求所需的記憶體太大。您要么需要使每個請求使用更少的內存,要么以某種方式限制並發性。
如果無論並發性如何,在處理一定數量的請求後出現問題,則存在記憶體洩漏。你需要找到它並回收記憶。
無論哪種情況,擁有一個好的堆記憶體分析器都會對您有很大幫助。有很好的商業工具,如 YourKit Java Profiler,也有免費的工具,如 Eclipse Memory Analyzer。找到適合您的工具並學習如何使用它來查看佔用記憶體的內容。請注意,您不一定需要使用該工具來啟動程式——如果您正在伺服器上執行負載測試,那麼您可以使用 JDK 中的 jmap 命令列工具來捕獲檔案中的堆轉儲,然後使用您的工具分析轉儲文件。該工具將向您顯示哪些物件佔用了堆中的空間。
答案2
有某物兩個系統之間存在差異,否則行為不會有所不同。請注意,在 GC 上花費太多時間而結果太少也可能導致錯誤。接近堆的限制運作會使GC出現此類問題。
GC 時間過長和 OutOfMemoryError
如果垃圾收集花費了太多時間,並發收集器將拋出 OutOfMemoryError:如果垃圾收集花費了總時間的 98% 以上,並且回收的堆少於 2%,則會拋出 OutOfMemoryError。此功能旨在防止應用程式長時間運行,但由於堆太小而幾乎沒有進展或沒有進展。如有必要,可以透過在命令列中新增選項 -XX:-UseGCOverheadLimit 來停用此功能。