傻瓜式jvm基礎學習
Q:jvm調優是在做什么?
A:通過修改jvm參數和更換合適的垃圾回收器從而達到提高垃圾回收效率、降低停頓時間,提高系統的吞吐量和響應速度。
從上面的問答中可以得到兩個概念,jvm參數、垃圾回收器。

程序計數器
存儲當前線程正在執行的Java方法的字節碼指令地址的內存區域,作為一個指示器使用,不會進行內存分配,因此不存在內存溢出的問題。
由于程序計數器是線程私有的,每個線程都有獨立的程序計數器。這確保了在多線程環境下,線程切換后能夠正確地恢復到上一個線程執行的位置。程序計數器在線程切換時起到了保持狀態的重要作用。
Java虛擬機棧
采用棧的數據結構來管理方法調用中的基本數據,先進后出(First In Last Out),每一個方法的調用使用一個棧幀(Stack Frame)來保存,虛擬機棧種保存著方法的局部變量、操作數棧(虛擬機在執行指令過程中用來存放臨時數據的一塊區域)、動態鏈接、方法返回地址(方法正常退出或異常退出的定義)和一些附加信息;局部變量的數量會影響到棧的深度
每個線程都會創建一個虛擬機棧,是線程私有的。棧的生命周期和線程同步一致,當線程線程結束,該虛擬機棧也就銷毀了。
本地方法棧
本地方法就是Java程序調用非Java代碼的接口,它的實現不是由Java語言實現。當Java程序需要和外間需要交互時,就可以選擇使用本地方法。
本地方法棧(Native Method Stack)用于本地方法的調用,線程私有,它允許被實現成固定大小或是可動態擴展的內存大小。程序使用本地方法棧的具體做法是:在本地方法棧中登記native方法,在執行引擎執行時加載本地方法庫。當某個線程調用一個本地方法時,它就進入了一個全新的且不受虛擬機限制的世界,它和虛擬機擁有同樣的權限。
HotSpot直接將本地方法棧和虛擬機棧合二為一。
堆區

堆是一種動態內存分配機制,用于存儲在程序運行過程中創建的對象。它是線程共享的,堆中的對象都需要考慮線程安全問題;存放引用數據類型的數據和new出來的的對象。
Jdk8后在邏輯上可以將堆區劃分為新生代和老年代。新生代又可以劃分為伊甸園區與幸存者區之間發生的內存整理行為是MinorGC,老年代發生的內存整理行為是MajorGC,整理堆區和方法區內存的行為是FullGC。
堆內存的大小可以在運行時進行調整,以滿足程序的需求。調整過程涉及到如下三個概念;used指的是當前已使用的堆內存,total是java虛擬機已經分配的可用堆內存,max是java虛擬機可以分配的最大堆內存。
在 Java 中,堆內存的分配和管理由垃圾回收器(Garbage Collector,簡稱 GC)負責。當對象不再被引用時,GC 會自動回收其占用的內存空間。
Java服務端程序開發時,建議將-Xmx和-Xms設置為相同的值,這樣在程序啟動之后可使用的總內存就是最大內存,而無需向java虛擬機再次申請,減少了申請并分配內存時間上的開銷,同時也不會出現內存過剩之后堆收縮的情況。
默認的新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數 –XX:NewRatio 來指定 ) , 即:新生代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小。其中,新生代 ( Young ) 被細分為 Eden 和 兩個 Survivor 區域, Edem 和倆個 Survivor 區域比例是 = 8 : 1 : 1 ( 可以通過參數 – XX:SurvivorRatio 來設定 ) ,但是 JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來為對象服務,所以 無論什么時候,總是有一塊 Survivor 區域是空閑著的。
方法區

用于存儲類型信息、方法信息、常量、及時編譯器編譯后的緩存代碼。方法區與Java堆一樣,是各個線程共享的內存區域,并且在JVM啟動時被創建,物理內存空間可以不連續,隨著JVM的關閉而釋放?。
在JDK 7以前,習慣上把方法區稱為永久代(習慣上),而到了JDK8,廢棄了永久代的概念,改用與JRockit、J9一樣在本地內存中實現的元空間(Metaspace)來代替。這兩個最大的區別就是:元空間不在虛擬機設置的內存中,而是使用本地內存。
jdk8 及之后使用參數 -XX:MetaspaceSize和-XX:MaxMetaspaceSize 來指定元空間的初始分配空間與最大可分配空間。在windows平臺下,初始元空間的默認可分配空間是 21M ,最大可分配空間參數值為 -1(-1表示不限制)。
如果不指定元空間可分配最大內存空間,極端情況下虛擬機會耗盡所有的可用系統內存,如果元空間區發生溢出,虛擬機會拋出異常:OutOfMenoryError:Metaspace
設置jvm內存的常用參數
|
參數類型 |
參數舉例 |
備注 |
|
堆最大值(max) |
-Xmx6M |
Xmx必須大于 2 MB,默認單位為字節(必須是1024的倍數)也可是指定單位k(K)、m(M)、g(G) |
|
堆初始值(total) |
-Xms6M |
Xms必須大于1MB,默認單位為字節(必須是1024的倍數)也可是指定單位k(K)、m(M)、g(G) |
|
Young區大小 |
-Xmn52M |
默認單位為字節,也可是指定單位k(K)、m(M)、g(G),GC操作在Young區比在其他區更頻繁。如果Young區的規模太小,那么將進行大量的小型垃圾收集。如果大小太大,則只會執行完整的垃圾收集,這可能需要很長時間才能完成。Oracle建議將Young區的堆大小保持在總堆大小的一半到四分之一之間 |
|
元空間的初始分配空間(MetaspaceSize) |
-XX:MetaspaceSize=128M |
設置元空間的大小,默認大小取決于平臺.當到達設定值之后會觸發FULLGC,如果設置為和MaxMetaspaceSize一樣大,就不會FULLGC,但是對象也無法回收。 |
|
元空間的最大可分配空間(MaxMetaspaceSize) |
-XX:MaxMetaspaceSize=512M |
設置元空間的最大內存量。默認情況下,大小不受限制。 |
|
Java虛擬機棧 |
-Xss128K |
默認單位為字節(必須是1024的倍數)也可是指定單位k(K)、m(M)、g(G),棧的大小直接決定了函數調用的最大可達深度,設置的值超過默認最大或者最小時設置失效。一般大小控制在1M之內 |
|
|
|
|
jvm參數模板
-Xms1g # 堆的初始值 -Xmx1g # 堆的最大值 -Xss256k # 棧大小 -XX:MaxMetaspaceSize=512m # 元空間的最大值 -XX:+DisableExplicitGC # 禁止在代碼中使用System.gc() -XX:+HeapDumpOnOutOfMemoryError # 發生OutOfMemoryError錯誤時,自動生成hprof內存快照文件 -XX:HeapDumpPath=/opt/logs/my-service.hprof # 指定hprof文件的輸出路徑 -XX:+PrintGCDetails # 打印GC詳細信息 -XX:+PrintGCDateStamps # GC時打印時間戳 -Xloggc:文件路徑 # GC日志生產路徑
Jdk8常用的垃圾回收器
|
垃圾回收器 |
簡介 |
目標 |
啟用參數 |
適用場景 |
|
?Serial收集器 |
Serial收集器是單線程的,在進行垃圾回收時會暫停所有用戶線程,直到回收結束 |
響應速度優先 |
-XX:+UseSerialGC |
單核處理器或客戶端模式下的虛擬機 |
|
?ParNew收集器?? |
ParNew是Serial收集器的多線程版本。它主要用于新生代垃圾回收,老年代則使用Serial Old |
響應速度優先 |
-XX:+UseParNewGC |
適用于多核處理器的server模式 |
|
?Parallel Scavenge收集器?? |
這是一個并行多線程收集器,Parallel Scavenge收集器可以與Serial Old或Parallel Old搭配使用 |
吞吐量優先 |
-XX:+UseParallelGC |
適用于服務端模式,適合響應時間要求不高的應用場景 |
|
?CMS(Concurrent Mark Sweep)收集器?? |
這是一種并發收集器。CMS收集器在垃圾回收時允許用戶線程繼續執行,但它在處理老年代時需要依賴新生代的收集器,如ParNew。 |
響應速度優先 |
-XX:+UseConcMarkSweepGC |
適用于追求低延遲的應用,例如互聯網網站或者bs系統 |
|
?G1(Garbage-First)收集器?? |
G1收集器旨在平衡吞吐量和停頓時間。G1將堆內存劃分為多個區域,并優先回收垃圾最多的區域,減少停頓時間 |
響應速度優先 |
-XX:+UseG1GC |
適用于大內存服務器和復雜應用 |
|
|
|
|
|
|
垃圾回收器的組合關系
由于垃圾回收器分為年輕代和老年代,除了G1之外其他垃圾回收器必須成對組合進行使用。


浙公網安備 33010602011771號