一點小經驗僅供參考:
1)堆
運行時數據區域,所有類實例和數組的內存均從此處分配。Java虛擬機啟動時創建。對象的堆內存由稱為垃圾回收器的自動內存管理系統回收。
堆由兩部分組成:
其中eden+fromspace+tospace也叫年輕代(young),oldspace叫舊生代.
其中還有S1,S0(在JDK的自帶工具輸出中會看到),分別指的是Survivorspace,存放每次垃圾回收后存活的對象.
OldGeneration,主要存放應用程序中生命周期長的存活對象
垃圾回收主要是對YoungGeneration塊和OldGeneration塊內存進行回收,YG用來放新產生的對象,經過幾次回收還沒回收掉的對象往OG中移動,
對YG進行垃圾回收又叫做MinorGC,對OG垃圾回收叫MajorGC,兩塊內存回收互不干涉
2)非堆內存
JVM具有一個由所有線程共享的方法區。方法區屬于非堆內存。它存儲每個類結構,如運行時常數池、字段和方法數據,以及方法和構造方法的代碼。它是在Java虛擬機啟動時創建的。
除了方法區外,Java虛擬機實現可能需要用于內部處理或優化的內存,這種內存也是非堆內存。例如,JIT編譯器需要內存來存儲從Java虛擬機代碼轉換而來的本機代碼,從而獲得高性能。
PermanentGeneration(圖中的PermanentSpace)存放JVM自己的反射對象,比如類對象和方法對象
3)回收算法和過程
JVM采用一種分代回收(generationalcollection)的策略,用較高的頻率對年輕的對象(younggeneration)進行掃描和回收,這種叫做minorcollection,而對老對象(oldgeneration)的檢查回收頻率要低很多,稱為majorcollection。這樣就不需要每次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區為新對象創建內存區域,則出現”outofmemory錯誤”
對象衰老的過程
younggeneration的內存,由一塊Eden(伊甸園,有意思)和兩塊SurvivorSpace(1.4文檔中稱為semi-space)構成。新創建的對象的內存都分配自eden。兩塊SurvivorSpace總有會一塊是空閑的,用作copyingcollection的目標空間。Minorcollection的過程就是將eden和在用survivorspace中的活對象copy到空閑survivorspace中。所謂survivor,也就是大部分對象在伊甸園出生后,根本活不過一次GC。對象在younggeneration里經歷了一定次數的minorcollection后,年紀大了,就會被移到oldgeneration中,稱為tenuring。(是否僅當survivorspace不足的時候才會將老對象tenuring?目前資料中沒有找到描述)
剩余內存空間不足會觸發GC,如eden空間不夠了就要進行minorcollection,oldgeneration空間不夠要進行majorcollection,permanentgeneration空間不足會引發fullGC。
4接下來這部分講解的是TOMCAT或者其他服務器出現如下錯誤時的分析:
1、首先是:java.lang.OutOfMemoryError:Javaheapspace
解釋:
Heapsize設置
JVM堆的設置是指java程序運行過程中JVM可以調配使用的內存空間的設置.JVM在啟動的時候會自動設置Heapsize的值,其初始空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)是物理內存的1/4??梢岳肑VM提供的-Xmn-Xms-Xmx等選項可進行設置。Heapsize的大小是YoungGeneration和TenuredGeneraion之和。
提示:在JVM中如果98%的時間是用于GC且可用的Heapsize不足2%的時候將拋出此異常信息。
提示:HeapSize最大不要超過可用物理內存的80%,一般的要將-Xms和-Xmx選項設置為相同,而-Xmn為1/4的-Xmx值。
解決方法:
手動設置Heapsize
修改TOMCAT_HOME/bin/catalina.bat,在“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:
Java代碼
setJAVA_OPTS=%JAVA_OPTS%-server-Xms800m-Xmx800m-XX:MaxNewSize=256m
setJAVA_OPTS=%JAVA_OPTS%-server-Xms800m-Xmx800m-XX:MaxNewSize=256m
或修改catalina.sh
在“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:
JAVA_OPTS="$JAVA_OPTS-server-Xms800m-Xmx800m-XX:MaxNewSize=256m"
2、其次是:java.lang.OutOfMemoryError:PermGenspace
原因:
PermGenspace的全稱是PermanentGenerationspace,是指內存的永久保存區域,這塊內存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到PermGenspace中,它和存放類實例(Instance)的Heap區域不同,GC(GarbageCollection)不會在主程序運行期對PermGenspace進行清理,所以如果你的應用中有很CLASS的話,就很可能出現PermGenspace錯誤,這種錯誤常見在web服務器對JSP進行precompile的時候。如果你的WEBAPP下都用了大量的第三方jar,其大小超過了jvm默認的大小(4M)那么就會產生此錯誤信息了。
解決方法:
1.手動設置MaxPermSize大小
修改TOMCAT_HOME/bin/catalina.bat(Linux下為catalina.sh),在Java代碼
“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:
setJAVA_OPTS=%JAVA_OPTS%-server-XX:PermSize=128M-XX:MaxPermSize=512m
“echo"UsingCATALINA_BASE:$CATALINA_BASE"”上面加入以下行:
setJAVA_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)(NewsGeneration和OldGeneraion之和)的設置
初始分配的內存由-Xms指定,默認是物理內存的1/64但小于1G。
最大分配的內存由-Xmx指定,默認是物理內存的1/4但小于1G。
默認空余堆內存小于40%時,JVM就會增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。
默認空余堆內存大于70%時,JVM會減少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。
服務器一般設置-Xms、-Xmx相等以避免在每次GC后調整堆的大小,所以上面的兩個參數沒啥用。
-Xmn設置younggeneration的heap大小
-XX:MinHeapFreeRatio與-XX:MaxHeapFreeRatio設定空閑內存占總內存的比例范圍,這兩個參數會影響GC的頻率和單次GC的耗時。-XX:NewRatio決定young與oldgeneration的比例。Younggeneration空間越大,minorcollection頻率越低,但是oldgeneration空間小了,又可能導致majorcollection頻率增加。-XX:NewSize和-XX:MaxNewSize直接指定了younggeneration的缺省大小和最大大小。
非堆內存的設置
默認分配為64M
-XX:PermSize設置最小分配空間,-XX:MaxPermSize設置最大分配空間。一般把這兩個數值設為相同,以減少申請內存空間的時間。
再講解和筆記下,JDK下的一些相關看內存管理工具的使用:
查看jvm內存狀態:
jstat-gcutilpid100020
異常情況的例子
jstat-gcutilpid100020
S0S1EOPYGCYGCTFGCFGCTGCT
0.000.0099.9982.5153.1124091.205101177250.3937251.598
0.000.0083.4282.5553.1024091.205101187252.6507253.855
0.000.0056.0682.4653.1024101.205101207254.4677255.672
0.000.0032.1182.5553.1024111.205101217256.6737257.877
0.000.0099.9982.5553.1024121.205101237257.0267258.231
0.000.0076.0082.5053.1024121.205101247259.2417260.446
這個數據顯示FullGC頻繁發生。
正常情況的例子
S0S1EOPYGCYGCTFGCFGCTGCT
0.000.000.2455.3999.601710.6671339393.364394.031
0.000.000.2455.3999.601710.6671339393.364394.031
0.000.000.2455.3999.601710.6671339393.364394.031
0.000.000.2455.3999.601710.6671339393.364394.031
0.000.000.2455.3999.601710.6671339393.364394.031
0.000.000.2455.3999.601710.6671339393.364394.031
參數含義:
S0:Heap上的Survivorspace0段已使用空間的百分比
S1:Heap上的Survivorspace1段已使用空間的百分比
E:Heap上的Edenspace段已使用空間的百分比
O:Heap上的Oldspace段已使用空間的百分比
P:Permspace已使用空間的百分比
YGC:從程序啟動到采樣時發生YoungGC的次數
YGCT:YoungGC所用的時間(單位秒)
FGC:從程序啟動到采樣時發生FullGC的次數
FGCT:FullGC所用的時間(單位秒)
GCT:用于垃圾回收的總時間(單位秒)
2Dump出內存
2.1找出要dump的線程pid
在Linux下,使用ps–aux
2.2Dump出內存使用詳情
可以通過命令:
jmap-dump:file=a.hprofpid
例如:jmap-heap2343,可以看到
AttachingtoprocessID2343,pleasewait...
Debuggerattachedsuccessfully.
Servercompilerdetected.
JVMversionis11.0-b16
usingthread-localobjectallocation.
ParallelGCwith8thread(s)
HeapConfiguration:
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)
HeapUsage:
PSYoungGeneration
EdenSpace:
capacity=1260060672(1201.6875MB)
used=64868288(61.86322021484375MB)
free=1195192384(1139.8242797851562MB)
5.148028935546367%used
FromSpace:
capacity=85524480(81.5625MB)
used=59457648(56.70323181152344MB)
free=26066832(24.859268188476562MB)
69.52120375359195%used
ToSpace:
capacity=85852160(81.875MB)
used=0(0.0MB)
free=85852160(81.875MB)
0.0%used
~~~~~~~~~~~~~~~~~~~~~~~~~~這三塊為上面所說的YG大小和使用情況
PSOldGeneration
capacity=2291138560(2185.0MB)
used=1747845928(1666.8757705688477MB)
free=543292632(518.1242294311523MB)
76.28722062099989%used
~~~~~~~~~~~~~~~~~~~~~~~~~~OG大小和使用情況
PSPermGeneration
capacity=108265472(103.25MB)
used=107650712(102.6637191772461MB)
free=614760(0.5862808227539062MB)
99.43217353728436%used
jstat
jstat是vm的狀態監控工具,監控的內容有類加載、運行時編譯及GC。
使用時,需加上查看進程的進程id,和所選參數。以下詳細介紹各個參數的意義。
jstat-classpid:顯示加載class的數量,及所占空間等信息。
jstat-compilerpid:顯示VM實時編譯的數量等信息。
jstat-gcpid:可以顯示gc的信息,查看gc的次數,及時間。其中最后五項,分別是younggc的次數,younggc的時間,fullgc的次數,fullgc的時間,gc的總時間。
jstat-gccapacity:可以顯示,VM內存中三代(young,old,perm)對象的使用和占用大小,如:PGCMN顯示的是最小perm的內存使用量,PGCMX顯示的是perm的內存最大使用量,PGC是當前新生成的perm內存占用量,PC是但前perm內存占用量。其他的可以根據這個類推,OC是old內純的占用量。
jstat-gcnewpid:new對象的信息。
jstat-gcnewcapacitypid:new對象的信息及其占用量。
jstat-gcoldpid:old對象的信息。
jstat-gcoldcapacitypid:old對象的信息及其占用量。
jstat-gcpermcapacitypid:perm對象的信息及其占用量。
jstat-utilpid:統計gc信息統計。
jstat-printcompilationpid:當前VM執行的信息。
除了以上一個參數外,還可以同時加上兩個數字,如:jstat-printcompilation30242506是每250毫秒打印一次,一共打印6次,還可以加上-h3每三行顯示一下標題。
例子:
jstat-gcutilpid100020
S0S1EOPYGCYGCTFGCFGCTGCT
47.490.0064.8246.0847.69208222058.6316822.7342081.365
0.0037.9138.5746.1347.69208232058.6916822.7342081.425這里發生了一次YGGC,也就是MinorGC,耗時0.06s
46.690.0015.1946.1847.69208242058.7766822.7342081.510
46.690.0074.5946.1847.69208242058.7766822.7342081.510
0.0040.2919.9546.2447.69208252058.8486822.7342081.582
MajorGC平均時間:22.734/68=0.334秒
MinorGC平均時間:2058.691/20823=0.099秒