最近,我在和一個朋友討論為什么Java進程使用的內存比啟動Java進程時設置的最大堆多。
代碼創建的所有Java對象都是在Java堆空間內創建的,其大小由-Xmx選項定義。 但是一個Java進程由很多空間組成,而不僅僅是Java堆空間。 以下是組成Java進程的一些空格:
- 加載的庫(包括jar和class文件)
- Java堆的控制結構
- 線程棧
- 生成的(JITed)代碼
- 用戶本機內存(在JNI中分配)
- … 更多…
在32位體系結構系統中,總進程大小不能超過4GB。 因此,一個32位的Java進程由許多空間(Java堆,本機內存(C-Heap)和其他空間)組成,并且其分配的空間不能超過4GB。
假設在32位生產系統上長時間運行具有-Xmx 1.5 GB(Java堆設置為1.5 GB)的Java應用程序服務器,并且已部署了許多應用程序。 一段時間后,客戶希望在同一應用程序服務器上部署更多應用程序。 系統運營商了解,由于服務器將不得不處理更多的請求,因此還需要創建更多的對象并進行更多的處理。 因此,作為將來的解決方案,運營商決定將Java進程的最大堆增加到2 GB。
好的,這看起來是個好方法,但是實際上在此生產應用程序服務器上發生了什么? (這是真實情況)。 應用程序服務器因OutOfMemoryError崩潰! 您能考慮一下可能的原因嗎?
我的第一個想法是2 GB的內存不足以支持所有這些應用程序。 不幸的是,問題出在別的地方。 您現在怎么看? 我會幫你一點。
java.lang.OutOfMemoryError: requested 55106896 bytes for Chunk::new.
真正的原因是,對于本機(C-Heap)內存,需要已部署的(舊)應用程序太大。 在操作員增加堆大小(從1.5GB到2 GB)之前,他們沒有監視舊應用程序所需的本機內存空間。 此操作的副作用是自動將Java進程本機內存的可用最大大小從2.5 GB減小到2GB。 由于舊的應用程序已經使用了如此大的本機內存,因此此更改會使服務器崩潰 !!!
在這種情況下,唯一可以接受的解決方案是避免增加最大堆大小,部署新應用程序并減少吞吐量。 這不是一個完美的解決方案,但這是在這種情況下唯一可行的解??決方案(因為我們的Java進程必須為32位)。
特別是在32位系統中,在增加Java堆大小之前,請注意Java進程本機內存的所需大小。 如果您處于這兩個空間沖突的情況,那么解決方案可能并非如此簡單。 如果您不能更改代碼來克服這種情況,那么最常見的解決方案是移至最大進程大小限制太大的64位系統。
有四件事要記住:
- 進程大小的最大限制
- Java進程的大小不僅由Java堆組成
- 無法明確配置Java進程的本機(C-Heap)內存的大小,因為Java堆空間可以實現
- 應用程序所需的Java堆空間和本機(C堆)內存空間的大小僅由應用程序定義,并且這兩個空間之間沒有任何標準比率
參考:來自 Java的JCG合作伙伴 Adrianos Dadis的Java堆空間,本機堆和內存問題 ,集成和源博客的優點 。
翻譯自: https://www.javacodegeeks.com/2013/01/java-heap-space-native-heap-and-memory-problems.html