JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)
堆、方法區(qū)、虛擬機(jī)棧、本地方法棧、程序計(jì)數(shù)器
線(xiàn)程共享數(shù)據(jù)區(qū):
堆:幾乎所有對(duì)象實(shí)例都要在堆上分配,可以通過(guò)-Xmx -Xms來(lái)控制;
方法區(qū):存放靜態(tài)變量、常量(在運(yùn)行時(shí)常量池中存放)、類(lèi)信息、JIT編譯后的代碼,(在JDK的HotSpot虛擬機(jī)中,可以認(rèn)為方法區(qū)就是永久代,但是在其他類(lèi)型的虛擬機(jī)中,沒(méi)有永久代的概念)可通過(guò)-XX:PermSize和-XX:MaxPermSize來(lái)指定最小值和最大值。
線(xiàn)程獨(dú)有數(shù)據(jù)區(qū):
虛擬機(jī)棧:存儲(chǔ)當(dāng)前線(xiàn)程運(yùn)行方法所需要的數(shù)據(jù)、指令、返回地址,其中一個(gè)方法對(duì)應(yīng)一個(gè)或多個(gè)棧幀(如果這個(gè)方法內(nèi)部調(diào)用了別的方法的話(huà)就會(huì)有多個(gè)),棧幀中存儲(chǔ)的有局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、出口;
本地方法棧:用于支持native方法的執(zhí)行,存儲(chǔ)了每個(gè)native方法調(diào)用的狀態(tài);
程序計(jì)數(shù)器:存儲(chǔ)當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)碼的行號(hào),幾乎不占什么內(nèi)存。
JVM內(nèi)存模型(JMM)
堆(新生代(Eden區(qū)+FromSurvivor+ToSurvivor)、老年代)+非堆(方法區(qū)or永久代)
新生代Eden區(qū)和S1、S2內(nèi)存大小比默認(rèn)是8:1:1,
新生代老年代內(nèi)存大小比默認(rèn)是1:2(因?yàn)橐娲髮?duì)象,所以?xún)?nèi)存設(shè)置比較大)
這樣劃分的目的是為了使 JVM 能夠更好的管理堆內(nèi)存中的對(duì)象,包括內(nèi)存的分配以及回收。對(duì)不同的年代區(qū),可以使用不同的算法進(jìn)行垃圾回收處理。
垃圾回收,有兩種算法:
- 引用計(jì)數(shù)法:其主要思想就是維護(hù)一個(gè)counter,當(dāng)counter為0的時(shí)候認(rèn)為對(duì)象沒(méi)有被引用,可以被回收。不足之處就是無(wú)法收集循環(huán)引用的對(duì)象。
- 可達(dá)性分析法:從gc root根據(jù)引用關(guān)系來(lái)遍歷整個(gè)堆并作標(biāo)記,稱(chēng)之為mark,之后回收掉未被mark的對(duì)象,好處是解決了循環(huán)依賴(lài)這種『孤島效應(yīng)』。gc root可以是方法區(qū)中的常量引用的對(duì)象或者靜態(tài)變量引用的對(duì)象,也可以是虛擬機(jī)棧中本地變量表中引用的對(duì)象,也可以是本地方法棧中的JNI(java native interface)引用的對(duì)象。
工作中經(jīng)常打交道的,也是GC收集垃圾的主要區(qū)域。
JVM最而發(fā)生在這三個(gè)地方的垃圾回收
新生代呢,一般用復(fù)制算法。
老年代呢,一般是大對(duì)象,大多都不會(huì)隨便死掉,也不怎么需要清理,所以就用標(biāo)記整理法。
GC回收器粗略分為2種,一種是在新生代活動(dòng)的,一種是在老年代活動(dòng)的。
新生代中,有哪幾種收集器?
serial(串行)、ParNew(并行)、Parallel Scavenge(并行),一般都使用parallel GC。
老年代呢?有哪幾種收集器?
Serial Old(串行,與Parallel Scavenger搭配使用)
CMS(目標(biāo):獲取最短回收停頓時(shí)間,標(biāo)記-清除)
Parallel Old(并行)
G1收集器:并行、并發(fā)、分代;初始標(biāo)記、并發(fā)標(biāo)記、最終標(biāo)記、篩選回收。
CMS和G1的區(qū)別是:G1不區(qū)分新生代和老年代,把堆空間分為大小想等的區(qū)域。
- Serial GC(-XX:+UseSerialGC):Serial GC使用簡(jiǎn)單的標(biāo)記、清除、壓縮方法對(duì)年輕代和年老代進(jìn)行垃圾回收,即Minor GC和Major GC。Serial GC在client模式(客戶(hù)端模式)很有用,比如在簡(jiǎn)單的獨(dú)立應(yīng)用和CPU配置較低的機(jī)器。這個(gè)模式對(duì)占有內(nèi)存較少的應(yīng)用很管用。
- Parallel GC(-XX:+UseParallelGC):除了會(huì)產(chǎn)生N個(gè)線(xiàn)程來(lái)進(jìn)行年輕代的垃圾收集外,Parallel GC和Serial GC幾乎一樣。這里的N是系統(tǒng)CPU的核數(shù)。我們可以使用 -XX:ParallelGCThreads=n 這個(gè)JVM選項(xiàng)來(lái)控制線(xiàn)程數(shù)量。并行垃圾收集器也叫throughput收集器。因?yàn)樗褂昧硕郈PU加快垃圾回收性能。Parallel GC在進(jìn)行年老代垃圾收集時(shí)使用單線(xiàn)程。
- Parallel Old GC(-XX:+UseParallelOldGC):和Parallel GC一樣。不同之處,Parallel Old GC在年輕代垃圾收集和年老代垃圾回收時(shí)都使用多線(xiàn)程收集。
- 并發(fā)標(biāo)記清除(CMS)收集器(-XX:+UseConcMarkSweepGC):CMS收集器也被稱(chēng)為短暫停頓并發(fā)收集器。它是對(duì)年老代進(jìn)行垃圾收集的。CMS收集器通過(guò)多線(xiàn)程并發(fā)進(jìn)行垃圾回收,盡量減少垃圾收集造成的停頓。CMS收集器對(duì)年輕代進(jìn)行垃圾回收使用的算法和Parallel收集器一樣。這個(gè)垃圾收集器適用于不能忍受長(zhǎng)時(shí)間停頓要求快速響應(yīng)的應(yīng)用??墒褂?-XX:ParallelCMSThreads=n JVM選項(xiàng)來(lái)限制CMS收集器的線(xiàn)程數(shù)量。
- G1垃圾收集器(-XX:+UseG1GC) G1(Garbage First):垃圾收集器是在Java 7后才可以使用的特性,它的長(zhǎng)遠(yuǎn)目標(biāo)時(shí)代替CMS收集器。G1收集器是一個(gè)并行的、并發(fā)的和增量式壓縮短暫停頓的垃圾收集器。G1收集器和其他的收集器運(yùn)行方式不一樣,不區(qū)分年輕代和年老代空間。它把堆空間劃分為多個(gè)大小相等的區(qū)域。當(dāng)進(jìn)行垃圾收集時(shí),它會(huì)優(yōu)先收集存活對(duì)象較少的區(qū)域,因此叫“Garbage First”。你可以在Oracle Garbage-FIrst收集器文檔找到更多詳細(xì)信息。
線(xiàn)上調(diào)優(yōu):
jdk提供的vm故障處理工具都比較實(shí)用,常用的jps,jstat,jmap,jstack以及可視化工具jconsole/visualvm,當(dāng)然根據(jù)個(gè)人實(shí)際實(shí)用情況
jps – jps是用來(lái)查看JVM里面所有進(jìn)程的具體狀態(tài), 包括進(jìn)程ID,進(jìn)程啟動(dòng)的路徑等等
jstack -- 如果java程序崩潰生成core文件,jstack工具可以用來(lái)獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發(fā)生問(wèn)題。另外,jstack工具還可以附屬到正在運(yùn)行的java程序中,看到當(dāng)時(shí)運(yùn)行的java程序的java stack和native stack的信息, 如果現(xiàn)在運(yùn)行的java程序呈現(xiàn)hung的狀態(tài),jstack是非常有用的。目前只有在Solaris和Linux的JDK版本里面才有。
jconsole – jconsole是基于Java Management Extensions (JMX)的實(shí)時(shí)圖形化監(jiān)測(cè)工具,這個(gè)工具利用了內(nèi)建到JVM里面的JMX指令來(lái)提供實(shí)時(shí)的性能和資源的監(jiān)控,包括了Java程序的內(nèi)存使用,Heap size, 線(xiàn)程的狀態(tài),類(lèi)的分配狀態(tài)和空間使用等等。
jinfo – jinfo可以從core文件里面知道崩潰的Java應(yīng)用程序的配置信息,目前只有在Solaris和Linux的JDK版本里面才有。
jmap – jmap 可以從core文件或進(jìn)程中獲得內(nèi)存的具體匹配情況,包括Heap size, Perm size等等,目前只有在Solaris和Linux的JDK版本里面才有。
jdb – jdb 用來(lái)對(duì)core文件和正在運(yùn)行的Java進(jìn)程進(jìn)行實(shí)時(shí)地調(diào)試,里面包含了豐富的命令幫助您進(jìn)行調(diào)試,它的功能和Sun studio里面所帶的dbx非常相似,但 jdb是專(zhuān)門(mén)用來(lái)針對(duì)Java應(yīng)用程序的。
jstat – jstat利用了JVM內(nèi)建的指令對(duì)Java應(yīng)用程序的資源和性能進(jìn)行實(shí)時(shí)的命令行的監(jiān)控,包括了對(duì)Heap size和垃圾回收狀況的監(jiān)控等等。
1、jps用來(lái)查看基于HotSpot的JVM里面中,所有具有訪(fǎng)問(wèn)權(quán)限的Java進(jìn)程的具體狀態(tài), 包括進(jìn)程ID,進(jìn)程啟動(dòng)的路徑及啟動(dòng)參數(shù)等等,與unix上的ps類(lèi)似,只不過(guò)jps是用來(lái)顯示java進(jìn)程,可以把jps理解為ps的一個(gè)子集。 使用jps時(shí),如果沒(méi)有指定hostid,它只會(huì)顯示本地環(huán)境中所有的Java進(jìn)程;如果指定了hostid,它就會(huì)顯示指定hostid上面的java進(jìn)程,不過(guò)這需要遠(yuǎn)程服務(wù)上開(kāi)啟了jstatd服務(wù),可以參看前面的jstatd章節(jié)來(lái)啟動(dòng)jstad服務(wù)。
命令格式 :jps [ options ] [ hostid ]
參數(shù)說(shuō)明 :
-q 忽略輸出的類(lèi)名、Jar名以及傳遞給main方法的參數(shù),只輸出pid。
-m 輸出傳遞給main方法的參數(shù),如果是內(nèi)嵌的JVM則輸出為null。
-l 輸出應(yīng)用程序主類(lèi)的完整包名,或者是應(yīng)用程序JAR文件的完整路徑。
-v 輸出傳給JVM的參數(shù)。
-V 輸出通過(guò)標(biāo)記的文件傳遞給JVM的參數(shù)(.hotspotrc文件,或者是通過(guò)參數(shù)-XX:Flags=<filename>指定的文件)。
-J 用于傳遞jvm選項(xiàng)到由javac調(diào)用的java加載器中,例如,“-J-Xms48m”將把啟動(dòng)內(nèi)存設(shè)置為48M,使用-J選項(xiàng)可以非常方便的向基于Java的開(kāi)發(fā)的底層虛擬機(jī)應(yīng)用程序傳遞參數(shù)。下面樣例均在linux的jdk1.7下測(cè)試
2、jstat
Jstat用于監(jiān)控基于HotSpot的JVM,對(duì)其堆的使用情況進(jìn)行實(shí)時(shí)的命令行的統(tǒng)計(jì),使用jstat我們可以對(duì)指定的JVM做如下監(jiān)控:
- 類(lèi)的加載及卸載情況
- 查看新生代、老生代及持久代的容量及使用情況
- 查看新生代、老生代及持久代的垃圾收集情況,包括垃圾回收的次數(shù)及垃圾回收所占用的時(shí)間
- 查看新生代中Eden區(qū)及Survior區(qū)中容量及分配情況等
jstat工具特別強(qiáng)大,它有眾多的可選項(xiàng),通過(guò)提供多種不同的監(jiān)控維度,使我們可以從不同的維度來(lái)了解到當(dāng)前JVM堆的使用情況。詳細(xì)查看堆內(nèi)各個(gè)部分的使用量,使用的時(shí)候必須加上待統(tǒng)計(jì)的Java進(jìn)程號(hào),可選的不同維度參數(shù)以及可選的統(tǒng)計(jì)頻率參數(shù)。
命令格式:jstat [ option vmid [interval][s|ms][count]]
option 參數(shù)如下面表格
[class] 用于查看類(lèi)加載情況的統(tǒng)計(jì)
interval 和count 代表查詢(xún)次數(shù)和間隔。
使用樣例:
[root@tools138 ~]# jstat -class 2897
Loaded Bytes Unloaded Bytes Time
67431 113866.2 59850 98607.5 1884.07
[root@tools138 ~]# jstat -compiler 2897
Compiled Failed Invalid Time FailedType FailedMethod
3782 1 0 507.88 1
org/apache/tomcat/util/IntrospectionUtils setProperty
jstat -gc 2897 100 10
表示查詢(xún)系統(tǒng)進(jìn)程為2897的java程序gc,每100毫秒查詢(xún)一次,一共查詢(xún)十次,顯示結(jié)果每列的含義如下:
S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
56832.0 57344.0 42356.2 0.0 235008.0 8153.1 699392.0 629319.5 119296.0 54057.7 66 3.869 3 1.772 5.642
S0C 新生代中Survivor space中S0當(dāng)前容量的大?。↘B)
S1U 新生代中Survivor space中S1容量使用的大?。↘B)
EU Eden space容量使用的大?。↘B)
OC Old space當(dāng)前容量的大?。↘B)
PU Permanent space使用容量的大小(KB)
YGC 從應(yīng)用程序啟動(dòng)到采樣時(shí)發(fā)生 Young GC 的次數(shù)
YGCT 從應(yīng)用程序啟動(dòng)到采樣時(shí) Young GC 所用的時(shí)間(秒)
FGC 從應(yīng)用程序啟動(dòng)到采樣時(shí)發(fā)生 Full GC 的次數(shù)
FGCT 從應(yīng)用程序啟動(dòng)到采樣時(shí) Full GC 所用的時(shí)間(秒)
GCTT 從應(yīng)用程序啟動(dòng)到采樣時(shí)用于垃圾回收的總時(shí)間(單位秒),它的值等于YGC+FGC
3、jinfo
jinfo可以輸出并修改運(yùn)行時(shí)的java 進(jìn)程的opts。用處比較簡(jiǎn)單,用于輸出JAVA系統(tǒng)參數(shù)及命令行參數(shù)。
命令格式:jinfo [option] pid
使用樣例:
[root@tools138 ~]# jinfo -flag MaxNewSize 2897
-XX:MaxNewSize=18446744073709486080
4、jmap
jmap用于生成堆轉(zhuǎn)儲(chǔ)快照(一般稱(chēng)為heapdump或者dump文件)。當(dāng)然也可其他方法比如加參數(shù)-XX:+HeapDumpOnOutOfMemoryError參數(shù),在虛擬機(jī)OOM異常的之后自動(dòng)生成dump文件,也可以通過(guò)-XX:+HeapDumpOnCtrlBreak參數(shù)則可以使用Ctrl+Break鍵讓虛擬機(jī)生成dump文件。在前文《 JAVA虛擬機(jī)之3:CMS垃圾收集器》測(cè)試中就有生成。dump文件生成后可借助jha、MAT( Eclipse Memory Analyzer tool)、IBM HeapAnalyzer來(lái)對(duì)dump分析。jmap不僅能獲取dump還可以查詢(xún)finalize執(zhí)行隊(duì)列,java堆和永久代詳細(xì)信息,空間使用率,當(dāng)前用的是什么收集器等。
jmap -J-d64 -heap pid
命令格式:jmap [ option ] pid
參數(shù)說(shuō)明:
-dump:[live,]format=b,file=<filename> 使用hprof二進(jìn)制形式,輸出jvm的heap內(nèi)容到文件=. live子選項(xiàng)是可選的,假如指定live選項(xiàng),那么只輸出活的對(duì)象到文件
-finalizerinfo 打印正等候回收的對(duì)象的信息
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情況
-histo[:live] 打印每個(gè)class的實(shí)例數(shù)目,內(nèi)存占用,類(lèi)全名信息. VM的內(nèi)部類(lèi)名字開(kāi)頭會(huì)加上前綴”*”. 如果live子參數(shù)加上后,只統(tǒng)計(jì)活的對(duì)象數(shù)量
-permstat 打印classload和jvm heap長(zhǎng)久層的信息. 包含每個(gè)classloader的名字,活潑性,地址,父classloader和加載的class數(shù)量. 另外,內(nèi)部String的數(shù)量和占用內(nèi)存數(shù)也會(huì)打印出來(lái)
-F 強(qiáng)迫.在pid沒(méi)有相應(yīng)的時(shí)候使用-dump或者-histo參數(shù). 在這個(gè)模式下,live子參數(shù)無(wú)效
使用樣例:
[root@tools138 ~]# jmap -dump:format=b,file=eclipse.bin 2897
Dumping heap to /root/eclipse.bin ...
Heap dump file created
6、jstack
jstack用于打印出給定的java進(jìn)程ID或core file或遠(yuǎn)程調(diào)試服務(wù)的Java堆棧信息,如果是在64位機(jī)器上,需要指定選項(xiàng)"-J-d64",Windows的jstack使用方式只支持以下的這種方式:
如果java程序崩潰生成core文件,jstack工具可以用來(lái)獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發(fā)生問(wèn)題。另外,jstack工具還可以附屬到正在運(yùn)行的java程序中,看到當(dāng)時(shí)運(yùn)行的java程序的java stack和native stack的信息, 如果現(xiàn)在運(yùn)行的java程序呈現(xiàn)hung的狀態(tài),jstack是非常有用的。