jvm内存 大于 xmx_为什么我的JVM访问的内存少于通过-Xmx指定的内存?
jvm內存 大于 xmx
“嘿,你能來看看奇怪的東西嗎?” 這就是我開始研究支持案例的方式,將我引向了這篇博客文章。 眼前的具體問題與報告可用內存數量不同的不同工具有關。
簡而言之,一位工程師正在研究特定應用程序的過多內存使用情況,據他所知,該應用程序可以使用2G的堆。 但是無論出于什么原因,JVM工具本身似乎都沒有決定該進程真正擁有多少內存。 例如, jconsole猜測總可用堆等于1,963M,而jvisualvm聲稱其等于2,048M。 那么哪個工具是正確的,為什么另一個卻顯示不同的信息呢?
確實確實很奇怪,尤其是看到通常的可疑對象都被淘汰了– JVM并沒有采取任何明顯的技巧,例如:
- -Xmx和-Xms相等,因此在運行時堆增加期間報告的數字不會更改
- 通過關閉自適應大小調整策略( -XX:-UseAdaptiveSizePolicy ),防止JVM動態調整內存池的大小
重現差異
理解問題的第一步是放大工具實現。 通過標準API訪問可用的內存信息非常簡單,如下所示:
System.out.println("Runtime.getRuntime().maxMemory()="+Runtime.getRuntime().maxMemory());確實,這就是手頭工具似乎正在使用的工具。 回答此類問題的第一步是擁有可重現的測試用例。 為此,我編寫了以下代碼段:
package eu.plumbr.test; //imports skipped for brevitypublic class HeapSizeDifferences {static Collection<Object> objects = new ArrayList<Object>();static long lastMaxMemory = 0;public static void main(String[] args) {try {List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();System.out.println("Running with: " + inputArguments);while (true) {printMaxMemory();consumeSpace();}} catch (OutOfMemoryError e) {freeSpace();printMaxMemory();}}static void printMaxMemory() {long currentMaxMemory = Runtime.getRuntime().maxMemory();if (currentMaxMemory != lastMaxMemory) {lastMaxMemory = currentMaxMemory;System.out.format("Runtime.getRuntime().maxMemory(): %,dK.%n", currentMaxMemory / 1024);}}static void consumeSpace() {objects.add(new int[1_000_000]);}static void freeSpace() {objects.clear();} }該代碼通過循環中的新int [1_000_000]分配內存塊,并檢查當前已知可用于JVM運行時的內存。 每當發現最后一個已知的內存大小發生變化時,它都會通過打印Runtime.getRuntime()。maxMemory()的輸出來報告該變化,類似于以下內容:
Running with: [-Xms2048M, -Xmx2048M] Runtime.getRuntime().maxMemory(): 2,010,112K.確實- 即使我已指定JVM使用2G堆,運行時也無法以某種方式找到其中的85M 。 您可以通過將Runtime.getRuntime()。maxMemory()的輸出轉換為MB(用2,010,112K除以1024 )來仔細檢查我的數學運算。結果將等于1,963M,與2048M相差85M。
尋找根本原因
在能夠重現案例之后,我記下了以下筆記–使用不同的GC算法運行似乎也會產生不同的結果:
| -XX:+ UseSerialGC | 2,027,264千 |
| -XX:+ UseParallelGC | 2,010,112千 |
| -XX:+ UseConcMarkSweepGC | 2,063,104千 |
| -XX:+ UseG1GC | 2,097,152千 |
除了G1完全消耗了我給該進程分配的2G內存外,其他所有GC算法似乎都始終丟失半隨機的內存。
現在是時候深入研究JVM 的源代碼了,在CollectedHeap的源代碼中,我發現了以下內容:
// Support for java.lang.Runtime.maxMemory(): return the maximum amount of // memory that the vm could make available for storing 'normal' java objects. // This is based on the reserved address space, but should not include space // that the vm uses internally for bookkeeping or temporary storage // (e.g., in the case of the young gen, one of the survivor // spaces). virtual size_t max_capacity() const = 0;我不得不承認答案是非常隱蔽的。 但是,仍然有一些真正的好奇心可以找到的提示–指的是在某些情況下,堆大小計算中可能會排除一個幸存空間 。
從這里一直是順風順水–打開GC日志記錄發現,實際上,使用2G堆,串行,并行和CMS算法都將幸存空間的大小恰好設置為缺少的差值。 例如,在上面的ParallelGC示例中,GC日志記錄演示了以下內容:
Running with: [-Xms2g, -Xmx2g, -XX:+UseParallelGC, -XX:+PrintGCDetails] Runtime.getRuntime().maxMemory(): 2,010,112K.... rest of the GC log skipped for brevity ...PSYoungGen total 611840K, used 524800K [0x0000000795580000, 0x00000007c0000000, 0x00000007c0000000)eden space 524800K, 100% used [0x0000000795580000,0x00000007b5600000,0x00000007b5600000)from space 87040K, 0% used [0x00000007bab00000,0x00000007bab00000,0x00000007c0000000)to space 87040K, 0% used [0x00000007b5600000,0x00000007b5600000,0x00000007bab00000)ParOldGen total 1398272K, used 1394966K [0x0000000740000000, 0x0000000795580000, 0x0000000795580000)從中您可以看到Eden空間設置為524,800K,兩個幸存者空間(從和到)都設置為87,040K,舊空間的大小為1,398,272K。 將Eden,Old和一個幸存者空間加在一起總計為2,010,112K,這證實丟失的85M或87,040K確實是剩余的幸存者空間 。
摘要
閱讀該文章后,您現在對Java API實現細節有了新的認識。 下次某些工具將總可用堆大小可視化為略小于Xmx指定的堆大小時,您會知道差值等于其中一個Survivor空間的大小。
我必須承認,這一事實在日常編程活動中并不是特別有用,但這不是該帖子的重點。 取而代之的是,我寫了一篇文章,描述了我一直在優秀工程師中尋找的一個特殊特性- 好奇心 。 優秀的工程師一直在尋找理解某件事如何以及為什么以它的方式起作用的方法。 有時答案仍然是隱藏的,但我仍然建議您嘗試尋求答案。 最終,沿途積累的知識將開始帶來紅利。
翻譯自: https://www.javacodegeeks.com/2015/02/jvm-access-less-memory-specified-via-xmx.html
jvm內存 大于 xmx
總結
以上是生活随笔為你收集整理的jvm内存 大于 xmx_为什么我的JVM访问的内存少于通过-Xmx指定的内存?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三星s10跟s10plus区别是什么
- 下一篇: ios怎么备份