回覆列表
  • 1 # Java程式設計師在搞機

    JVM 記憶體結構,JVM的啟動引數,GC的機制,以及問題出現後透過堆dump或者執行緒抽樣進行問題分析,針對問題進行最佳化

  • 2 # 使用者4631824322

    一點小經驗僅供參考:

    1) 堆

    執行時資料區域,所有類例項和陣列的記憶體均從此處分配。Java 虛擬機器啟動時建立。物件的堆記憶體由稱為垃圾回收器 的自動記憶體管理系統回收。

    堆由兩部分組成:

    其中eden+fromspace+tospace也叫年輕代(young),old space叫舊生代.

    其中還有S1,S0(在JDK的自帶工具輸出中會看到),分別指的是Survivor space,存放每次垃圾回收後存活的物件.

    Old Generation , 主要存放應用程式中生命週期長的存活物件

    垃圾回收主要是對Young Generation塊和Old Generation塊記憶體進行回收,YG用來放新產生的物件,經過幾次回收還沒回收掉的物件往OG中移動,

    對YG進行垃圾回收又叫做MinorGC,對OG垃圾回收叫MajorGC,兩塊記憶體回收互不干涉

    2) 非堆記憶體

    JVM具有一個由所有執行緒共享的方法區。方法區屬於非堆記憶體。它儲存每個類結構,如執行時常數池、欄位和方法資料,以及方法和構造方法的程式碼。它是在 Java 虛擬機器啟動時建立的。

    除了方法區外,Java 虛擬機器實現可能需要用於內部處理或最佳化的記憶體,這種記憶體也是非堆記憶體。 例如,JIT 編譯器需要記憶體來儲存從 Java 虛擬機器程式碼轉換而來的本機程式碼,從而獲得高效能。

    Permanent Generation (圖中的Permanent Space) 存放JVM自己的反射物件,比如類物件和方法物件

    3) 回收演算法和過程

    JVM採用一種分代回收 (generational collection) 的策略,用較高的頻率對年輕的物件(young generation)進行掃描和回收,這種叫做minor collection,而對老物件(old generation)的檢查回收頻率要低很多,稱為major collection。這樣就不需要每次GC都將記憶體中所有物件都檢查一遍。

    當一個URL被訪問時,記憶體申請過程 如下:

    A. JVM會試圖為相關Java物件在Eden中初始化一塊記憶體區域

    B. 當Eden空間足夠時,記憶體申請結束。否則到下一步

    C. JVM試圖釋放在Eden中所有不活躍的物件(這屬於1或更高階的垃圾回收), 釋放後若Eden空間仍然不足以放入新物件,則試圖將部分Eden中活躍物件放入Survivor區

    D. Survivor區被用來作為Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的物件會被移到Old區,否則會被保留在Survivor區

    E. 當OLD區空間不夠時,JVM會在OLD區進行完全的垃圾收集(0級)

    F. 完全垃圾收集後,若Survivor及OLD區仍然無法存放從Eden複製過來的部分物件,導致JVM無法在Eden區為新物件建立記憶體區域,則出現”out of memory錯誤”

    物件衰老的過程

    young generation的記憶體,由一塊Eden(伊甸園,有意思)和兩塊Survivor Space(1.4文件中稱為semi-space)構成。新建立的物件的記憶體都分配自eden。兩塊Survivor Space總有會一塊是空閒的,用作copying collection的目標空間。Minor collection的過程就是將eden和在用survivor space中的活物件copy到空閒survivor space中。所謂survivor,也就是大部分物件在伊甸園出生後,根本活不過一次GC。物件在young generation裡經歷了一定次數的minor collection後,年紀大了,就會被移到old generation中,稱為tenuring。(是否僅當survivor space不足的時候才會將老物件tenuring? 目前資料中沒有找到描述)

    剩餘記憶體空間不足會觸發GC,如eden空間不夠了就要進行minor collection,old generation空間不夠要進行major collection,permanent generation空間不足會引發full GC。

    4 接下來這部分講解的是TOMCAT或者其他伺服器出現如下錯誤時的分析:

    1、首先是:java.lang.OutOfMemoryError: Java heap space

    解釋:

    Heap size 設定

    JVM堆的設定是指java程式執行過程中JVM可以調配使用的記憶體空間的設定.JVM在啟動的時候會自動設定Heap size的值,其初始空間(即-Xms)是物理記憶體的1/64,最大空間(-Xmx)是物理記憶體的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設定。Heap size 的大小是Young Generation 和Tenured Generaion 之和。

    提示:在JVM中如果98%的時間是用於GC且可用的Heap size 不足2%的時候將丟擲此異常資訊。

    提示:Heap Size 最大不要超過可用物理記憶體的80%,一般的要將-Xms和-Xmx選項設定為相同,而-Xmn為1/4的-Xmx值。

    解決方法:

    手動設定Heap size

    修改TOMCAT_HOME/bin/catalina.bat,在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

    Java程式碼

    set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m

    set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m

    或修改catalina.sh

    在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

    JAVA_OPTS="$JAVA_OPTS -server -Xms800m -Xmx800m -XX:MaxNewSize=256m"

    2、其次是:java.lang.OutOfMemoryError: PermGen space

    原因:

    PermGen space的全稱是Permanent Generation space,是指記憶體的永久儲存區域,這塊記憶體主要是被JVM存放Class和Meta資訊的,Class在被Loader時就會被放到PermGen space中,它和存放類例項(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程式執行期對PermGen space進行清理,所以如果你的應用中有很CLASS的話,就很可能出現PermGen space錯誤,這種錯誤常見在web伺服器對JSP進行pre compile的時候。如果你的WEB APP下都用了大量的第三方jar, 其大小超過了jvm預設的大小(4M)那麼就會產生此錯誤資訊了。

    解決方法:

    1. 手動設定MaxPermSize大小

    修改TOMCAT_HOME/bin/catalina.bat(Linux下為catalina.sh),在Java程式碼

    “echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

    set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m

    “echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

    set JAVA_OPTS=%JAVA_OPTS% -server -XX:PermSize=128M -XX:MaxPermSize=512m

    catalina.sh下為:

    Java程式碼

    JAVA_OPTS="$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m"

    JAVA_OPTS="$JAVA_OPTS -server -XX:PermSize=128M -XX:MaxPermSize=512m"

    JVM的預設設定

    堆 (heap)(News Generation 和Old Generaion 之和)的設定

    初始分配的記憶體由-Xms指定,預設是物理記憶體的1/64但小於1G。

    最大分配的記憶體由-Xmx指定,預設是物理記憶體的1/4但小於1G。

    預設空餘堆記憶體小於40%時,JVM就會增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。

    預設空餘堆記憶體大於70%時,JVM會減少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。

    伺服器一般設定-Xms、-Xmx相等以避免在每次GC 後調整堆的大小,所以上面的兩個引數沒啥用。

    -Xmn 設定young generation的heap大小

    -XX:MinHeapFreeRatio與-XX:MaxHeapFreeRatio設定空閒記憶體佔總記憶體的比例範圍,這兩個引數會影響GC的頻率和單次GC的耗時。-XX:NewRatio決定young與old generation的比例。Young generation空間越大,minor collection頻率越低,但是old generation空間小了,又可能導致major collection頻率增加。-XX:NewSize和-XX:MaxNewSize直接指定了young generation的預設大小和最大大小。

    非堆記憶體 的設定

    預設分配為64M

    -XX:PermSize設定最小分配空間,-XX:MaxPermSize設定最大分配空間。一般把這兩個數值設為相同,以減少申請記憶體空間的時間。

    再講解和筆記下,JDK下的一些相關看記憶體管理工具的使用:

    檢視jvm記憶體狀態:

    jstat -gcutil pid 1000 20

    異常情況的例子

    jstat -gcutil pid 1000 20

    S0 S1 E O P YGC YGCT FGC FGCT GCT

    0.00 0.00 99.99 82.51 53.11 2409 1.205 10117 7250.393 7251.598

    0.00 0.00 83.42 82.55 53.10 2409 1.205 10118 7252.650 7253.855

    0.00 0.00 56.06 82.46 53.10 2410 1.205 10120 7254.467 7255.672

    0.00 0.00 32.11 82.55 53.10 2411 1.205 10121 7256.673 7257.877

    0.00 0.00 99.99 82.55 53.10 2412 1.205 10123 7257.026 7258.231

    0.00 0.00 76.00 82.50 53.10 2412 1.205 10124 7259.241 7260.446

    這個資料顯示Full GC頻繁發生。

    正常情況的例子

    S0 S1 E O P YGC YGCT FGC FGCT GCT

    0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

    0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

    0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

    0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

    0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

    0.00 0.00 0.24 55.39 99.60 171 0.667 1339 393.364 394.031

    引數含義:

    S0:Heap上的 Survivor space 0 段已使用空間的百分比

    S1:Heap上的 Survivor space 1 段已使用空間的百分比

    E: Heap上的 Eden space 段已使用空間的百分比

    O: Heap上的 Old space 段已使用空間的百分比

    P: Perm space 已使用空間的百分比

    YGC:從程式啟動到取樣時發生Young GC的次數

    YGCT:Young GC所用的時間(單位秒)

    FGC:從程式啟動到取樣時發生Full GC的次數

    FGCT:Full GC所用的時間(單位秒)

    GCT:用於垃圾回收的總時間(單位秒)

    2 Dump出記憶體

    2.1 找出要dump的執行緒pid

    在Linux下,使用ps –aux

    2.2 Dump出記憶體使用詳情

    可以透過命令:

    jmap -dump:file=a.hprof pid

    例如:jmap -heap 2343,可以看到

    Attaching to process ID 2343, please wait...

    Debugger attached successfully.

    Server compiler detected.

    JVM version is 11.0-b16

    using thread-local object allocation.

    Parallel GC with 8 thread(s)

    Heap Configuration:

    MinHeapFreeRatio = 40

    MaxHeapFreeRatio = 70

    MaxHeapSize = 4294967296 (4096.0MB)

    NewSize = 2686976 (2.5625MB)

    MaxNewSize = -65536 (-0.0625MB)

    OldSize = 5439488 (5.1875MB)

    NewRatio = 2 (YG,OG 大小比為1:2)

    SurvivorRatio = 8

    PermSize = 21757952 (20.75MB)

    MaxPermSize = 268435456 (256.0MB)

    Heap Usage:

    PS Young Generation

    Eden Space:

    capacity = 1260060672 (1201.6875MB)

    used = 64868288 (61.86322021484375MB)

    free = 1195192384 (1139.8242797851562MB)

    5.148028935546367% used

    From Space:

    capacity = 85524480 (81.5625MB)

    used = 59457648 (56.70323181152344MB)

    free = 26066832 (24.859268188476562MB)

    69.52120375359195% used

    To Space:

    capacity = 85852160 (81.875MB)

    used = 0 (0.0MB)

    free = 85852160 (81.875MB)

    0.0% used

    ~~~~~~~~~~~~~~~~~~~~~~~~~~這三塊為上面所說的YG大小和使用情況

    PS Old Generation

    capacity = 2291138560 (2185.0MB)

    used = 1747845928 (1666.8757705688477MB)

    free = 543292632 (518.1242294311523MB)

    76.28722062099989% used

    ~~~~~~~~~~~~~~~~~~~~~~~~~~OG大小和使用情況

    PS Perm Generation

    capacity = 108265472 (103.25MB)

    used = 107650712 (102.6637191772461MB)

    free = 614760 (0.5862808227539062MB)

    99.43217353728436% used

    jstat

    jstat是vm的狀態監控工具,監控的內容有類載入、執行時編譯及GC。

    使用時,需加上檢視程序的程序id,和所選引數。以下詳細介紹各個引數的意義。

    jstat -class pid:顯示載入class的數量,及所佔空間等資訊。

    jstat -compiler pid:顯示VM實時編譯的數量等資訊。

    jstat -gc pid:可以顯示gc的資訊,檢視gc的次數,及時間。其中最後五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。

    jstat -gccapacity:可以顯示,VM記憶體中三代(young,old,perm)物件的使用和佔用大小,如:PGCMN顯示的是最小perm的記憶體使用量,PGCMX顯示的是perm的記憶體最大使用量,PGC是當前新生成的perm記憶體佔用量,PC是但前perm記憶體佔用量。其他的可以根據這個類推, OC是old內純的佔用量。

    jstat -gcnew pid:new物件的資訊。

    jstat -gcnewcapacity pid:new物件的資訊及其佔用量。

    jstat -gcold pid:old物件的資訊。

    jstat -gcoldcapacity pid:old物件的資訊及其佔用量。

    jstat -gcpermcapacity pid: perm物件的資訊及其佔用量。

    jstat -util pid:統計gc資訊統計。

    jstat -printcompilation pid:當前VM執行的資訊。

    除了以上一個引數外,還可以同時加上 兩個數字,如:jstat -printcompilation 3024 250 6是每250毫秒列印一次,一共列印6次,還可以加上-h3每三行顯示一下標題。

    例子:

    jstat -gcutil pid 1000 20

    S0 S1 E O P YGC YGCT FGC FGCT GCT

    47.49 0.00 64.82 46.08 47.69 20822 2058.631 68 22.734 2081.365

    0.00 37.91 38.57 46.13 47.69 20823 2058.691 68 22.734 2081.425 這裡發生了一次YG GC,也就是MinorGC,耗時0.06s

    46.69 0.00 15.19 46.18 47.69 20824 2058.776 68 22.734 2081.510

    46.69 0.00 74.59 46.18 47.69 20824 2058.776 68 22.734 2081.510

    0.00 40.29 19.95 46.24 47.69 20825 2058.848 68 22.734 2081.582

    MajorGC平均時間:22.734/68=0.334秒

    MinorGC平均時間:2058.691/20823=0.099秒

  • 中秋節和大豐收的關聯?
  • 百萬醫療險都可以報銷哪些費用?有需要注意的事情嗎?