预留空间过大的OutOfMemoryError
在分配一個應該很適合我為JVM提供的堆中的數據結構時,為什么會出現OutOfMemoryError? 這是我最近遇到的一個問題。
確實,當查看開發人員要完成的工作并通過-Xmx參數對提供給JVM的堆大小進行三重檢查時,似乎確實存在著一些可疑之處。
30分鐘后,我們了解了情況并解開了謎團。 但這確實起初并不明顯,所以我認為如果我更詳細地描述根本問題,可能會節省一天的時間。
與往常一樣,理解問題的最佳方法是通過動手實例。 我構建了一個小的綜合測試用例:
package eu.plumbr.demo; class ArraySize {public static void main(String... args) {int[] array = new int[1024*1024*1024];} }代碼很簡單–它要做的就是分配一個包含十億個元素的數組。 現在,考慮到java int原語需要4個字節,因此人們可能會認為使用6g堆運行代碼會很好地運行。 畢竟,這十億個整數應該只消耗4g內存。 那么為什么執行代碼時會看到以下內容?
My Precious:bin me$ java –Xms6g –Xmx6g eu.plumbr.demo.ArraySize Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat eu.plumbr.demo.ArraySize.main(ArraySize.java:6)在投入更多的堆之前(事實上,使用–Xmx7g ,上面的示例運行得很好),讓我們嘗試了解為什么我們的期望是錯誤的。
首先– Java中的int原語確實需要4個字節。 因此,這并不是說我們的JVM實現一夜之間變得瘋狂。 而且我可以向您保證,數學運算也是正確的-1024 * 1024 * 1024 int原語確實需要4,294,967,296字節或4 GB。
要了解發生了什么,讓我們運行相同的情況,并通過指定–XX:+ PrintGCDetails來打開垃圾收集日志記錄:
My Precious:bin me$ java –Xms6g -Xmx6g -XX:+PrintGCDetails eu.plumbr.demo.ArraySize-- cut for brevity --Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat eu.plumbr.demo.ArraySize.main(ArraySize.java:6)HeapPSYoungGen total 1835008K, used 125829K [0x0000000780000000, 0x0000000800000000, 0x0000000800000000)eden space 1572864K, 8% used [0x0000000780000000,0x0000000787ae15a8,0x00000007e0000000)from space 262144K, 0% used [0x00000007e0000000,0x00000007e0000000,0x00000007f0000000)to space 262144K, 0% used [0x00000007f0000000,0x00000007f0000000,0x0000000800000000)ParOldGen total 4194304K, used 229K [0x0000000680000000, 0x0000000780000000, 0x0000000780000000)object space 4194304K, 0% used [0x0000000680000000,0x0000000680039608,0x0000000780000000)PSPermGen total 21504K, used 2589K [0x000000067ae00000, 0x000000067c300000, 0x0000000680000000)object space 21504K, 12% used [0x000000067ae00000,0x000000067b087668,0x000000067c300000)答案現在正盯著我們的眼睛:即使我們有很多可用的總堆,堆中的單個區域也沒有足夠大的空間來容納4g對象。 我們的6g堆分為四個單獨的區域,大小如下:
- 伊甸園15.36億
- 生存空間( 從和向 )每個256M
- 老一代4,096M
現在,牢記對象分配必須適合單個區域,我們確實可以看到應用程序沒有機會–在我們的任何堆區域中都沒有足夠的空間來容納此4g分配。
那么–我們現在唯一的希望是進一步增加堆數嗎? 即使我們已經提供了將近50%的超額配置–將6g堆交給一個應該適合4g的數據結構? 沒那么快-有替代解決方案可用。 您可以設置內存中不同區域的大小。 它并不像人們期望的那樣簡單明了,而且用戶友好,但是對啟動配置進行兩次小的修改就可以解決問題。 使用兩個額外的選項啟動相同的代碼時:
My Precious:bin me$ java -Xms6g -Xmx6g -XX:NewSize=5g -XX:SurvivorRatio=10 eu.plumbr.demo.ArraySize然后程序執行其工作,并且不會引發OutOfMemoryError。 在啟動中添加-XX:+ PrintGCDetails也會對此進行說明:
HeapPSYoungGen total 4806144K, used 4369080K [0x00000006c0000000, 0x0000000800000000, 0x0000000800000000)eden space 4369408K, 99% used [0x00000006c0000000,0x00000007caaae228,0x00000007cab00000)from space 436736K, 0% used [0x00000007e5580000,0x00000007e5580000,0x0000000800000000)to space 436736K, 0% used [0x00000007cab00000,0x00000007cab00000,0x00000007e5580000)ParOldGen total 1048576K, used 0K [0x0000000680000000, 0x00000006c0000000, 0x00000006c0000000)object space 1048576K, 0% used [0x0000000680000000,0x0000000680000000,0x00000006c0000000)PSPermGen total 21504K, used 2563K [0x000000067ae00000, 0x000000067c300000, 0x0000000680000000)object space 21504K, 11% used [0x000000067ae00000,0x000000067b080c90,0x000000067c300000)我們看到,現在的區域大小確實是我們所要求的:
- 如我們的-XX:NewSize = 5g參數所指定,年輕大小int總數(eden +兩個幸存者空間)為5g
- 如我們用-XX:SurvivorRatio = 10參數指定的,Eden比幸存者大10倍。
請注意,在我們的情況下,兩個參數都是必需的。 僅指定-XX:NewSize = 5g仍會以某種方式將其在伊甸園和幸存者之間分割,使得任何區域都無法容納所需的4g。
希望閱讀此說明將為您節省以后的調試時間。 或幫助您避免過度配置資源。
翻譯自: https://www.javacodegeeks.com/2014/05/outofmemoryerror-on-overprovisioned-heap.html
總結
以上是生活随笔為你收集整理的预留空间过大的OutOfMemoryError的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓光标软件(安卓光标)
- 下一篇: Neo4j 2.1:传递节点ID与UNW