JVM堆內存相關的啟動參數:年輕代、老年代和永久代的內存分配


如果想觀察JVM進程占用的堆內存,可以通過命令工具jmap或者可視化工具jvisualvm.exe。JVM這些啟動參數都擁有默認值,如果想了解JVM的內存分配策略,最好手動設置這些啟動參數。再通過JDK提供的工具的統計結果,進行對比,就比較容易理解這些內存分配的理論知識。運行環境是win7 32位操作系統,JDK1.7.0_60版本。

測試代碼和JVM啟動參數如下:

public class Test { public static void main(String[] args) { int a = 0; while (true) { a++; } } }
-Xms=200M  -Xmx200M -XX:NewSize=100M -Xmn100M -XX:SurvivorRatio=8
-XX:OldSize=60M -XX:PermSize=50M -XX:MaxPermSize=50M

運行上述代碼,通過jps命令獲取到進程pid,然后通過jmap -heap pid就可以查看內存分配和使用情況。

>jmap -heap 8912 Attaching to process ID 8912, please wait... Debugger attached successfully. Client compiler detected. JVM version is 24.60-b09 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 209715200 (200.0MB) NewSize = 104857600 (100.0MB) MaxNewSize = 104857600 (100.0MB) OldSize = 62914560 (60.0MB) NewRatio = 3 SurvivorRatio = 8 PermSize = 52428800 (50.0MB) MaxPermSize = 52428800 (50.0MB)

這里顯示的堆配置參數,都可以通過JVM啟動參數來設置。下面來解釋下幾個重要參數的含義:

-Xms 和 -Xmx (-XX:InitialHeapSize 和 -XX:MaxHeapSize):指定JVM初始占用的堆內存和最大堆內存。JVM也是一個軟件,也必須要獲取本機的物理內

存,然后JVM會負責管理向操作系統申請到的內存資源。JVM啟動的時候會向操作系統申請 -Xms 設置的內存,JVM啟動后運行一段時間,如果發現內存空間

不足,會再次向操作系統申請內存。JVM能夠獲取到的最大堆內存是-Xmx設置的值。

-XX:NewSize 和 -Xmn(-XX:MaxNewSize):指定JVM啟動時分配的新生代內存和新生代最大內存。

-XX:SurvivorRatio:設置新生代中1個Eden區與1個Survivor區的大小比值。在hotspot虛擬機中,新生代 = 1個Eden + 2個Survivor。如果新生代內存是

10M,SurvivorRatio=8,那么Eden區占8M,2個Survivor區各占1M。

-XX:NewRatio:指定老年代/新生代的堆內存比例。在hotspot虛擬機中,堆內存 = 新生代 + 老年代。如果-XX:NewRatio=4表示年輕代與年老代所占比值為1:4,年輕代占整個堆內存的1/5。在設置了-XX:MaxNewSize的情況下,-XX:NewRatio的值會被忽略,老年代的內存=堆內存 - 新生代內存。老年代的最大內存 = 堆內存 - 新生代 最大內存。 

-XX:OldSize:設置JVM啟動分配的老年代內存大小,類似於新生代內存的初始大小-XX:NewSize。

-XX:PermSize 和 -XX:MaxPermSize:指定JVM中的永久代(方法區)的大小。可以看到:永久代不屬於堆內存,堆內存只包含新生代和老年代

可以發現:堆內存、新生代內存、老年代內存、永久代內存,都有一個初始內存,還有一個最大內存。下面以老年代的初始內存和最大內存為例,看下內存變化的效果,其他的應該類似。測試代碼如下:

public class TurnedTest { private static List<string> list = new ArrayList<string>(); public static void main(String[] args) { int a = 0; while (true) { a++; list.add("demo"); } } }

顯然這個程序存在內存泄露,最終會占滿整個堆內存,拋出OOM。為了看清楚這個演變的過程,我們在while循環中添加一個斷點,設置breakpoint properties中的"hit count"為100000,以debug模式運行上面的程序,然后使用jmap觀察內存占用情況。

tenured generation: capacity = 62914560 (60.0MB) used = 0 (0.0MB) free = 62914560 (60.0MB) 0.0% used tenured generation: capacity = 62914560 (60.0MB) used = 16409080 (15.648918151855469MB) free = 46505480 (44.35108184814453MB) 26.08153025309245% used tenured generation: capacity = 62914560 (60.0MB) used = 53329496 (50.858970642089844MB) free = 9585064 (9.141029357910156MB) 84.76495107014973% used tenured generation: capacity = 104857600 (100.0MB) used = 84217880 (80.3164291381836MB) free = 20639720 (19.683570861816406MB) 80.3164291381836% used

可以發現老年代內存從最開始的60M,擴大到最大值100M。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM