- 虛擬機(jī)大致分為系統(tǒng)虛擬機(jī)(vmware,可運(yùn)行完整操作系統(tǒng)的軟件平臺(tái))和程序虛擬機(jī)(jvm,專門為執(zhí)行當(dāng)個(gè)計(jì)算機(jī)程序而設(shè)計(jì)),在上面運(yùn)行的軟件都被限制于虛擬機(jī)提供的資源中
- 虛擬機(jī)的基本結(jié)構(gòu)
1.類加載子系統(tǒng):負(fù)責(zé)從文件系統(tǒng)或網(wǎng)絡(luò)中加載class信息悄晃,存放到方法區(qū),也就是一塊內(nèi)存空間
2.*方法區(qū):存放類信息凤价,常量信息,常量池信息挖炬,包括字符串字面量和數(shù)字常量等
3.*java堆:jvm啟動(dòng)的時(shí)候建立java堆揽浙,java程序最主要的內(nèi)存工作區(qū)域状婶,幾乎所有的對(duì)象實(shí)例都放在java堆中,堆空間是所有線程共享的馅巷,
4.直接內(nèi)存:java的nio庫(kù)允許java程序使用直接內(nèi)存膛虫,從而提高性能,通常直接內(nèi)存速度會(huì)優(yōu)于java堆钓猬,讀寫頻繁的場(chǎng)合可能會(huì)考慮使用
5.*java棧:每個(gè)虛擬機(jī)線程都有一個(gè)私有的棧稍刀,線程棧在線程創(chuàng)建的時(shí)候被創(chuàng)建,線程棧中保存著局部變量敞曹,方法參數(shù)账月,java的方法調(diào)用,返回值等等
6.本地方法棧和java棧非常類似 澳迫,但是本地方法棧用于java調(diào)用本地方法(通常使用c編寫)
7.*java 自己的一套進(jìn)行垃圾清理的機(jī)制局齿,稍后詳細(xì)說明
8.pc寄存器,每個(gè)線程的私有空間橄登,jvm會(huì)為每個(gè)線程創(chuàng)建pc寄存器抓歼,在任意時(shí)刻,一個(gè)java線程總是在執(zhí)行一個(gè)方法拢锹,這個(gè)方法稱為當(dāng)前方法谣妻,如果當(dāng)前方法不是本地方法,pc寄存器就會(huì)執(zhí)行當(dāng)前正在被執(zhí)行的指令卒稳,如果是本地方法蹋半,pc寄存器值為undefined,pc寄存器存放如當(dāng)前執(zhí)行環(huán)境指針充坑,程序計(jì)數(shù)器减江,操作棧指針,計(jì)算的變量指針等
9.*虛擬機(jī)最核心的組件捻爷,負(fù)責(zé)執(zhí)行虛擬機(jī)的字節(jié)碼您市,一般會(huì)先進(jìn)行編譯成機(jī)器碼后執(zhí)行
帶*的是重要部分
類加載之后一些信息(類信息,靜態(tài)信息被存放于方法區(qū)中役衡,快永久區(qū)Perm)
類被實(shí)例化之后茵休,被存儲(chǔ)到j(luò)ava堆中,一塊內(nèi)存空間
當(dāng)我們使用對(duì)象的時(shí)候手蝎,其實(shí)用的是這塊內(nèi)存空間的引用
這個(gè)引用存放在java棧中
- java堆詳解
- 幾乎所有的對(duì)象都放在其中榕莺,java堆是自動(dòng)化管理的,通過垃圾回收機(jī)制棵介,垃圾對(duì)象會(huì)自動(dòng)清理钉鸯,不需要顯示的釋放
- 根據(jù)垃圾回收機(jī)制的不同,java堆可能會(huì)有不同的結(jié)構(gòu)邮辽,最常見的是將整個(gè)java堆分為新生代和老年代唠雕,新生代存放新生的對(duì)象或者年齡不大的對(duì)象贸营,老年代則存放老年對(duì)象
- 新生代分為eden區(qū),s0區(qū)岩睁,s1區(qū)钞脂,s0和s1區(qū)也被稱為from和to區(qū)域,他們是倆塊大小相等并且可以互換角色的空間
- 絕大多數(shù)情況下捕儒,對(duì)象首先分配在eden區(qū)冰啃,在一次新生代回收后,如果對(duì)象還存活刘莹,則會(huì)進(jìn)入s0或者s1區(qū)(或者的原因是在任意時(shí)間s0和s1只能有一塊在使用)阎毅,之后每經(jīng)過一次新生代回收,如果對(duì)象存活則它的年齡就加1点弯,當(dāng)對(duì)象達(dá)到一定年齡(閾值)后扇调,則進(jìn)入老年代(tenured區(qū),表明在一定考量后抢肛,這個(gè)數(shù)據(jù)一直被引用肃拜,老年區(qū)的數(shù)據(jù)不會(huì)被頻繁的回收,新生代則會(huì)被頻繁回收)
- s0和s1區(qū)存在的意義在于雌团,這倆塊區(qū)域的垃圾回收使用的是復(fù)制算法,核心思想是將內(nèi)存空間分為倆塊士聪,每次只使用其中一塊锦援,垃圾回收時(shí),將正在使用的內(nèi)存中的存留對(duì)象復(fù)制到未被使用的內(nèi)存塊中去剥悟,之后去清除之前正在使用的內(nèi)存塊中的所有對(duì)象灵寺,反復(fù)去交換倆個(gè)內(nèi)存的角色,完成垃圾收集区岗。
- java 棧
- 線程私有的內(nèi)存空間略板,一個(gè)棧一般有三部分組成:局部變量表,操作數(shù)棧和幀數(shù)據(jù)區(qū)
- 局部變量表:用于保存函數(shù)的參數(shù)及局部變量
- 操作數(shù)棧:主要保存計(jì)算過程的中間結(jié)果慈缔,同時(shí)作為計(jì)算過程中變量臨時(shí)的存儲(chǔ)空間
- 幀數(shù)據(jù)區(qū):除了局部變量表和操作數(shù)棧之外叮称,棧還需要一些數(shù)據(jù)來支持常量池的解析,幀數(shù)據(jù)區(qū)保存著常量池的指針藐鹤,方便程序訪問常量池瓤檐,此外,當(dāng)函數(shù)返回或者出現(xiàn)異常時(shí)娱节,虛擬機(jī)必須有一個(gè)異常處理表挠蛉,方便發(fā)送異常的時(shí)候找到異常的代碼,因此異常處理表也是幀數(shù)據(jù)區(qū)的一部分肄满。
- java方法區(qū)
- 和堆一樣谴古,方法區(qū)是一塊所有線程共享的內(nèi)存區(qū)域质涛,它保存系統(tǒng)的類信息,比如類的字段掰担,方法汇陆,常量池等,方法區(qū)的大小決定了系統(tǒng)可以保存多少個(gè)類恩敌,如果系統(tǒng)定義太多的類瞬测,導(dǎo)致方法區(qū)溢出。虛擬機(jī)同樣會(huì)拋出內(nèi)存溢出錯(cuò)誤纠炮。方法區(qū)可以理解為永久區(qū)(Perm)
- 虛擬機(jī)參數(shù)
- 圍繞堆月趟,棧,方法區(qū)恢口,垃圾回收機(jī)制 配置
- 堆分配參數(shù):
- -xx:+PrintGC 虛擬機(jī)啟動(dòng)后孝宗,只要遇到GC就會(huì)打印日志
- -xx:+UseSerialGC 配置串行回收器
- -xx:+PrintGCDetails gc時(shí)可以查看詳細(xì)信息,包括各個(gè)區(qū)的情況
- -Xms java程序啟動(dòng)時(shí)初始堆大小
- -Xmx java程序能獲得的最大堆大小
- -Xmn 設(shè)置新生代大小耕肩,這個(gè)參數(shù)對(duì)gc有較大影響因妇,一般設(shè)置為整個(gè)堆大小的三分之一到四分之一左右
- -XX:SurvivorRatio 設(shè)置新生代中eden空間和from或to空間的比例,如果等于3猿诸,說明eden區(qū)比上from或to區(qū)為3:1
- -XX:NewRatio 設(shè)置新生代和老年代的比例
- -XX:+PrintCommandLineFlags 可以將虛擬機(jī)的參數(shù)輸出
- 總結(jié)婚被,實(shí)際工作中可以將初始堆大小和最大堆大小設(shè)置相等,這樣可以減少程序運(yùn)行時(shí)的垃圾回收次數(shù)梳虽,從而提高性能
-
GCdetails解讀
- def new generation 新生代址芯,分為eden區(qū),from區(qū)窜觉,to區(qū)谷炸,后面幾列是總空間,使用空間百分比禀挫,最后是內(nèi)存地址
- tenured generation 老年代旬陡,后面幾列是總空間,使用空間百分比语婴,最后是內(nèi)存地址
- compacting perm gen 永久區(qū)(perm)
- 堆溢出處理
- 如果堆空間不足描孟,則會(huì)拋出內(nèi)存溢出的錯(cuò)誤(Out Of Memory,OOM)砰左,這類問題如果發(fā)生在生產(chǎn)環(huán)境画拾,可能會(huì)引起嚴(yán)重的業(yè)務(wù)中斷.
- -XX:HeapDumpOnOutOfMemoryError,使用該參數(shù)可以再內(nèi)存溢出時(shí)導(dǎo)出整個(gè)堆信息
- -XX:HeapDumpPath 設(shè)置導(dǎo)出堆信息的存放路徑,與上面的參數(shù)配合使用
- 例子:
-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test03.dump - dump文件分析工具
- 分析方法
- 代碼示例
public static void main(String[] args) { //-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test03.dump //堆內(nèi)存溢出 Vector v = new Vector(); for(int i=0; i < 5; i ++){ v.add(new Byte[1*1024*1024]); } }
- 棧參數(shù)配置
- -Xss 指定單個(gè)線程的最大棽酥埃空間青抛,棧空間的大小直接決定了函數(shù)可調(diào)用的最大深度
- 代碼示例
public class Test04 { //-Xss1m //-Xss5m //棧調(diào)用深度 private static int count; public static void recursion(){ count++; recursion(); } public static void main(String[] args){ try { recursion(); } catch (Throwable t) { System.out.println("調(diào)用最大深入:" + count); t.printStackTrace(); } } }
- 方法區(qū)參數(shù)配置
- 方法區(qū)保存系統(tǒng)的類信息
- 默認(rèn)情況下酬核,-XX:MaxPermSize 為64MB蜜另,如果系統(tǒng)運(yùn)行時(shí)產(chǎn)生大量的類适室,就需要設(shè)置一個(gè)相對(duì)合適的方法區(qū),以免永久區(qū)內(nèi)存溢出的問題
- -XX:PermSize 初始化方法區(qū)大小
- -XX:MaxPermSize 方法區(qū)最大大小
- 直接內(nèi)存參數(shù)配置
- -XX:MaxDirectMemorySize举瑰,如果不設(shè)置捣辆,默認(rèn)值為最大堆空間,即-Xmx此迅,直接內(nèi)存使用達(dá)到上限時(shí)汽畴,會(huì)觸發(fā)垃圾回收,如果不能有效的釋放空間耸序,也會(huì)引起系統(tǒng)的OOM忍些,
- jdk1.7之后,不再關(guān)注這個(gè)參數(shù)坎怪,配不配都沒什么大影響
- Client和Server虛擬機(jī)工作模式
- 只有在jdk1.7之前罢坝,jdk才分這倆個(gè)模式,1.7之后不再提供client模式搅窿,使用-client參數(shù)使用Client模式嘁酿,使用-server使用Server模式,
- 區(qū)別
- Client模式啟動(dòng)較快男应,適用于測(cè)試闹司,不追求系統(tǒng)的長(zhǎng)時(shí)間使用性能
- Server模式啟動(dòng)較慢,會(huì)對(duì)虛擬機(jī)的性能進(jìn)行負(fù)載的系統(tǒng)性能信息收集和使用更復(fù)雜的算法對(duì)程序進(jìn)行優(yōu)化沐飘,長(zhǎng)期運(yùn)行性能遠(yuǎn)遠(yuǎn)快于client模式
- 關(guān)于jvm的博客參考