一、JVM結構
二、運行時數據區分爲以下幾塊空間:
- 1、堆(Heap):保存所有引用類型的真實數據,此區爲共享區。
- 2、虛擬機棧(VM Stack):虛擬機棧描述的是Java 方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作棧、動態鏈接、方法出口等信息。
方法調用時棧幀的動作:
- 3、方法區(Method Data Area):所有定義的方法的信息都保存在方法區之中,此區爲共享區。
- 4、程序計數器:程序計數器是一塊較小的內存空間,可以看作是當前線程所執行的字節碼的行號指示器。分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。
- 5、本地方法棧:本地方法棧(Native MethodStacks)與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧爲虛擬機執行Java 方法(也就是字節碼)服務,而本地方法棧則是爲虛擬機使用到的Native 方法服務。
三、JVM堆分爲三塊:
年輕代:新對象和沒達到一定年齡的對象都在年輕代。
- 1、伊甸園區:所有的新對象都在伊甸園區產生。
2、存活區:存活區分爲兩塊相等大小的區域S0和S1。伊甸園區中經過多次Minor GC後還存活的活躍對象將會晉升到存活區。
分爲兩塊相同大小區域的目的:一塊爲了晉升,一塊爲了對象回收。這兩塊內存空間一定有一塊是空的。
3、伸縮區:用於調整年輕代內存大小的緩衝區。
修改年輕代內存調整參數:
例如:-Xmx16g -Xms16g -XX:SurvivorRatio=6 -XX:+PrintGCDetails
設置Eden區和Survivor爲“6:1:1”
年輕代GC(Minor GC)回收算法
描述:將伊甸園區的存活對象複製到存活區兩塊區域中空的那塊,然後另外一塊區域中的活躍對象根據其存活時間判斷是保存到另塊空間還是保存到老年代。然後清除不活躍對象,騰出空間。
在整個處理過程中,伊甸園區中保存的對象有可能大部分都臨時對象,那麼這樣就有可能頻繁的發生Minor GC,所以在HotSpot虛擬機中爲了加快此空間的內存分配,採用了兩種技術:
1、Bump-The-Pointer
缺點:多線程下有多個對象並行創建,就會影響性能。
2、TLAB(Thread-Local-Allocation Buffers)
老年代:被長時間使用的對象,老年代的內存空間比年輕代大。如果保存的對象超過了伊甸園區的內存大小,此對象將直接保存到老年代。
例如:-Xmx16g -Xms16g -XX:PretenureSizeThreshold=512k -XX:+PrintGCDetails
如果有超過512k的對象直接保存到老年代,這個對象不會再觸發Minor GC。老年代GC(Major GC/Full GC)回收算法
- 1、標記-清除
先對老年代中不活躍對象進行標記,標記完成之後進行清除,不會對清除後的空間進行整理,會導致內存碎片化問題。 - 2、標記-壓縮
先對老年代中不活躍對象進行標記,標記完成之後進行清除,清除之後再對空間碎片進行整理壓縮。
- 1、標記-清除
永久代和元空間:永久代在JDK1.8之後被元空間替代。目的是將HotSpot與JRockit兩個虛擬機標準統一。
永久代(JDK1.8以前):永久代是在堆內存中保存的,但是永久代不會被回收,例如:intern()產生的對象就不會被回收。如果操作不當,導致永久代內存溢出,也會拋出“OutOfMemoryError”異常。
永久代參數調整:
例如:-XX:MaxPermSize=10m 結果:
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10m; support was removed in 8.0
在JDK1.8之後就不存在永久代的設置了。元空間(JDK1.8以後):功能和永久代沒太大區別。唯一的區別是永久代使用的堆內存而元空間是使用的物理內存。
元空間內存參數調整:
例如:-XX:MetaspaceSize=1m -XX:MaxMetaspaceSize=1m
Error occurred during initialization of VM
OutOfMemoryError: Metaspace
如果元空間內存太小也會“OOM”
四、堆內存參數調整(測試機器內存24G)
1、初始化內存和最大內存
public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); System.out.println("maxMemory:" + maxMemory / 1024 / 1024 + "M"); System.out.println("totalMemory:" + totalMemory / 1024 / 1024 + "M"); } maxMemory:5452M totalMemory:368M
可以發現:默認情況下分配的內存是總內存的“1/4”,初始化內存大小是物理內存的“1/64”,也就是說可變內存是物理內存的“1/64 ~ 1/4”。
手動指定最大內存和初始化內存 -Xmx8G -Xms8G 再次輸入結果爲:
maxMemory:7851M totalMemory:7851M
這個時候就避免了伸縮區的可調策略,從而提高了程序的性能
2、觀察GC的詳細日誌:-XX:+PrintGCDetails
控制檯輸出:
maxMemory:7851M totalMemory:7851M Heap PSYoungGen total 2446848K, used 167813K [0x0000000715580000, 0x00000007c0000000, 0x00000007c0000000) eden space 2097664K, 8% used [0x0000000715580000,0x000000071f961618,0x0000000795600000) from space 349184K, 0% used [0x00000007aab00000,0x00000007aab00000,0x00000007c0000000) to space 349184K, 0% used [0x0000000795600000,0x0000000795600000,0x00000007aab00000) ParOldGen total 5592576K, used 0K [0x00000005c0000000, 0x0000000715580000, 0x0000000715580000) object space 5592576K, 0% used [0x00000005c0000000,0x00000005c0000000,0x0000000715580000) Metaspace used 3532K, capacity 4498K, committed 4864K, reserved 1056768K class space used 387K, capacity 390K, committed 512K, reserved 1048576K
PSYoungGen:新生代 3/8
ParOldGen:老年代 5/8
默認情況下新生代和老年代內存大小比例爲:3:53、內存可視化工具:
1、可視化工具:\jdk1.8.0_131\bin\jvisualvm.exe
1)、繼續執行上步代碼,將內存調整爲最大內存調整爲16G,方便查看過程。
-Xmx16g -Xms16g -XX:+PrintGCDetails
- 2)、運行程序,打開jvisualvm.exe找到當前執行的進程,打開監視,可以觀察到CPU、堆等使用情況。
2、命令查看:jmap(jmap -heap PID)
1)、運行程序,Windows下打開cmd,輸入taskList 找到 java.exe 觀察其PID
C:\Users\Administrator>tasklist 映像名稱 PID 會話名 會話# 內存使用 ========================= ======== ================ =========== ============ java.exe 10280 Console 1 5,241,504 K
2)、再輸入 jmap -heap 10280 即可觀察到內存使用情況
C:\Users\Administrator>jmap -heap 10280 Attaching to process ID 10280, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.131-b11 using thread-local object allocation. Parallel GC with 8 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 734003200 (700.0MB) NewSize = 134217728 (128.0MB) MaxNewSize = 244318208 (233.0MB) OldSize = 268435456 (256.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 100663296 (96.0MB) used = 18841312 (17.968475341796875MB) free = 81821984 (78.03152465820312MB) 18.717161814371746% used From Space: capacity = 16777216 (16.0MB) used = 6625856 (6.31890869140625MB) free = 10151360 (9.68109130859375MB) 39.49317932128906% used To Space: capacity = 16777216 (16.0MB) used = 0 (0.0MB) free = 16777216 (16.0MB) 0.0% used PS Old Generation capacity = 268435456 (256.0MB) used = 81936 (0.0781402587890625MB) free = 268353520 (255.92185974121094MB) 0.03052353858947754% used 5342 interned Strings occupying 461016 bytes.