JVM運(yùn)行時內(nèi)存結(jié)構(gòu)_第1頁
JVM運(yùn)行時內(nèi)存結(jié)構(gòu)_第2頁
JVM運(yùn)行時內(nèi)存結(jié)構(gòu)_第3頁
JVM運(yùn)行時內(nèi)存結(jié)構(gòu)_第4頁
JVM運(yùn)行時內(nèi)存結(jié)構(gòu)_第5頁
已閱讀5頁,還剩20頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、1.JVM內(nèi)存模型JVM運(yùn)行時內(nèi)存=共享內(nèi)存區(qū)+線程內(nèi)存區(qū)1).共享內(nèi)存區(qū)共享內(nèi)存區(qū)=持久帶+堆持久帶=方法區(qū)+其他堆=Old Space+Young SpaceYoung Space=Eden+S0+S1(1)持久帶JVM用持久帶(Permanent Space)實(shí)現(xiàn)方法區(qū),主要存放所有已加載的類信息,方法信息,常量池等等??赏ㄟ^-XX:PermSize和-XX:MaxPermSize來指定持久帶初始化值和最大值。Permanent Space并不等同于方法區(qū),只不過是Hotspot JVM用Permanent Space來實(shí)現(xiàn)方法區(qū)而已,有些虛擬機(jī)沒有Permanent Space而用其他

2、機(jī)制來實(shí)現(xiàn)方法區(qū)。(2)堆堆,主要用來存放類的對象實(shí)例信息。堆分為Old Space(又名,Tenured Generation)和Young Space。Old Space主要存放應(yīng)用程序中生命周期長的存活對象;Eden(伊甸園)主要存放新生的對象;S0和S1是兩個大小相同的內(nèi)存區(qū)域,主要存放每次垃圾回收后Eden存活的對象,作為對象從Eden過渡到Old Space的緩沖地帶(S是指英文單詞Survivor Space)。堆之所以要劃分區(qū)間,是為了方便對象創(chuàng)建和垃圾回收,后面垃圾回收部分會解釋。2).線程內(nèi)存區(qū)線程內(nèi)存區(qū)=單個線程內(nèi)存+單個線程內(nèi)存+.單個線程內(nèi)存=PC Regster+J

3、VM棧+本地方法棧JVM棧=棧幀+棧幀+.棧幀=局域變量區(qū)+操作數(shù)區(qū)+幀數(shù)據(jù)區(qū)在Java中,一個線程會對應(yīng)一個JVM棧(JVM Stack),JVM棧里記錄了線程的運(yùn)行狀態(tài)。JVM棧以棧幀為單位組成,一個棧幀代表一個方法調(diào)用。棧幀由三部分組成:局部變量區(qū)、操作數(shù)棧、幀數(shù)據(jù)區(qū)。(1)局部變量區(qū)局部變量區(qū),可以理解為一個以數(shù)組形式進(jìn)行管理的內(nèi)存區(qū),從0開始計數(shù),每個局部變量的空間是32位的,即4字節(jié)?;绢愋蚥yte、char、short、boolean、int、float及對象引用等占一個局部變量空間,類型為short、byte和char的值在存入數(shù)組前要被轉(zhuǎn)換成int值;long、double

4、占兩個局部變量空間,在訪問long和double類型的局部變量時,只需要取第一個變量空間的索引即可,。例如:?1234567public static int runClassMethod(int i,long l,float f,double d,Object o,byte b)        return 0;        

5、0;         public int runInstanceMethod(char c,double d,short s,boolean b)        return 0;   對應(yīng)的局域變量區(qū)是:runInstanceMethod的局部變量區(qū)第一項(xiàng)是個reference(引用),它指定的就是對象本身的引用,也就是我們

6、常用的this,但是在runClassMethod方法中,沒這個引用,那是因?yàn)閞unClassMethod是個靜態(tài)方法。(2)操作數(shù)棧操作數(shù)棧和局部變量區(qū)一樣,也被組織成一個以字長為單位的數(shù)組。但和前者不同的是,它不是通過索引來訪問的,而是通過入棧和出棧來訪問的。操作數(shù)棧是臨時數(shù)據(jù)的存儲區(qū)域。例如:?123int a= 100;int b =5;int c = a+b;對應(yīng)的操作數(shù)棧變化為:從圖中可以得出:操作數(shù)棧其實(shí)就是個臨時數(shù)據(jù)存儲區(qū)域,它是通過入棧和出棧來進(jìn)行操作的。PS:JVM實(shí)現(xiàn)里,有一種基于棧的指令集(Hotsp

7、ot,oracle JVM),還有一種基于寄存器的指令集(DalvikVM,安卓 JVM),兩者有什么區(qū)別的呢?基于棧的指令集有接入簡單、硬件無關(guān)性、代碼緊湊、棧上分配無需考慮物理的空間分配等優(yōu)勢,但是由于相同的操作需要更多的出入棧操作,因此消耗的內(nèi)存更大。 而基于寄存器的指令集最大的好處就是指令少,速度快,但是操作相對繁瑣。示例:?1234567891011121314package com.demo3; public class Test      public static

8、60;void foo()         int a = 1;        int b = 2;        int c = (a + b) * 5;    

9、60;    public static void main(String args)         foo();    基于棧的Hotspot的執(zhí)行過程如下:基于寄存器的DalvikVM執(zhí)行過程如下所示:上述兩種方式最終通過JVM執(zhí)行引擎,CPU接收到的匯編指令是:(3)幀數(shù)據(jù)區(qū) 幀數(shù)據(jù)區(qū)存放了指向常量池的指針地址,當(dāng)某些指令需要獲得常量池的數(shù)據(jù)時,通過幀數(shù)據(jù)區(qū)中的指針地址

10、來訪問常量池的數(shù)據(jù)。此外,幀數(shù)據(jù)區(qū)還存放方法正常返回和異常終止需要的一些數(shù)據(jù)。2.垃圾回收機(jī)制1)、為什么要垃圾回收J(rèn)VM自動檢測和釋放不再使用的內(nèi)存,提高內(nèi)存利用率。 Java 運(yùn)行時JVM會執(zhí)行 GC,這樣程序員不再需要顯式釋放對象。 2)、回收哪些內(nèi)存區(qū)域因?yàn)榫€程內(nèi)存區(qū)隨著線程的產(chǎn)生和退出而分配和回收,所以垃圾回收主要集中在共享內(nèi)存區(qū),也就是持久帶(Permanent Space)和堆(Heap)。3)、如何判斷對象已死 (對象標(biāo)記)(1)引用計數(shù)法引用計數(shù)法就是通過一個計數(shù)器記錄該對象被引用的次數(shù),方法簡單高效,但是解決不了循環(huán)引用的問題。比如對象A包含指向?qū)ο驜的

11、引用,對象B也包含指向?qū)ο驛的引用,但沒有引用指向A和B,這時當(dāng)前回收如果采用的是引用計數(shù)法,那么對象A和B的被引用次數(shù)都為1,都不會被回收。JVM不是采用這種方法。(2) 根搜索(可達(dá)性分析算法)根搜索(可達(dá)性分析算法)可以解決對象循環(huán)引用的問題,基本原理是:通過一個叫“GC ROOT”根對象作為起點(diǎn),然后根據(jù)關(guān)聯(lián)關(guān)系,向下節(jié)點(diǎn)搜索,搜索路徑叫引用鏈,也就是常說的引用。從“GC ROOT”根對象找不到任何一條路徑與之相連的對象,就被判定可以回收,相當(dāng)于這對象找不到家的感覺。示例圖:GC會收集那些不是GC root且沒有被GC root引用的對象。一個對象可以屬于多個GC root。

12、GC root有幾下種:· 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象· 方法區(qū)中類靜態(tài)屬性引用的對象· 方法區(qū)中常量引用的對象· 本地方法棧中JNI(native方法)引用的對象· 用于JVM特殊目的對象,例如系統(tǒng)類加載器等等雖然有可達(dá)性分析算法來判定對象狀態(tài),但這并不是對象是否被回收的條件,對象回收的條件遠(yuǎn)遠(yuǎn)比這個復(fù)雜。無法通過GC ROOT關(guān)聯(lián)到的對象,不都是立刻被回收。如果這個對象沒有被關(guān)聯(lián)到,而且沒有被mark2標(biāo)記,那么會進(jìn)入一個死緩的階段,被第一次標(biāo)記(mark1),然后被放入一個F-Queue隊列;如果這個對象被mark2標(biāo)記了

13、,那么這個對象將會被回收。F-Queue隊列由一個優(yōu)先級較低的Finalizer線程去執(zhí)行,其中的mark1對象等待執(zhí)行自己的finalize()方法(JVM并不保證等待finalize()方法運(yùn)行結(jié)束,因?yàn)閒inalize() 方法或者執(zhí)行慢,或者死循環(huán),會影響該隊列其他元素執(zhí)行)。執(zhí)行mark1對象的finalize()方法,就會進(jìn)行第二次標(biāo)記(mark2)。以后的GC都會按這個邏輯執(zhí)行“搜索,標(biāo)記1,標(biāo)記2”。這一“標(biāo)記”過程是后續(xù)垃圾回收算法的基礎(chǔ)。PS:· 如果在finalize() 方法體內(nèi),再次對本對象進(jìn)行引用,那么對象就復(fù)活了。· finalize()方法只

14、會被執(zhí)行一次,所以對象只有一次復(fù)活的機(jī)會。3)垃圾回收算法垃圾回收算法主要有三種:· 標(biāo)記-清除· 標(biāo)記-復(fù)制· 標(biāo)記-整理這三種都有“標(biāo)記”過程,這個標(biāo)記過程就是上述的根搜索(可達(dá)性分析算法)。后面的“清除”、“復(fù)制”和“整理”動作,是具體的對象被回收的實(shí)現(xiàn)方式。(1)標(biāo)記-清除通過根搜索(可達(dá)性分析算法)標(biāo)記完成后,直接將標(biāo)記為垃圾的對象所占內(nèi)存空間釋放。這種算法的缺點(diǎn)是內(nèi)存碎片多。雖然缺點(diǎn)明顯,這種策略卻是后兩種策略的基礎(chǔ)。正因?yàn)樗娜秉c(diǎn),所以促成了后兩種策略的產(chǎn)生。(2)標(biāo)記-復(fù)制通過根搜索(可達(dá)性分析算法)標(biāo)記完成后,將內(nèi)存分為兩塊,將一塊內(nèi)存中保留的對

15、象全部復(fù)制到另一塊空閑內(nèi)存中。這種算法的缺點(diǎn)是,可用內(nèi)存變成了一半。怎么解決這個缺點(diǎn)呢?JVM將堆(heap)分成young區(qū)和old區(qū)。young區(qū)包括eden、s0、s1,并且三個區(qū)之間的大小有一定比例。例如,按8:1:1分成一塊Eden和兩小塊Survivor區(qū),每次GC時,young區(qū)里,將Eden和S0中存活的對象復(fù)制到另一塊空閑的S1中。young區(qū)的垃圾回收是經(jīng)常要發(fā)生的,被稱為Minor GC(次要回收)。一般情況下,當(dāng)新對象生成,并且在Eden申請空間失敗時,就會觸發(fā)Minor GC,對Eden區(qū)域進(jìn)行GC,清除非存活對象,并且把尚且存活的對象移動到Survivor區(qū)。然后整

16、理Survivor的兩個區(qū)。這種方式的GC是對Young space的Eden區(qū)進(jìn)行,不會影響到Old space。因?yàn)榇蟛糠謱ο蠖际菑腅den區(qū)開始的,同時Eden區(qū)不會分配的很大,所以Eden區(qū)的GC會頻繁進(jìn)行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。Minor GC主要過程:a、新生成的對象在Eden區(qū)完成內(nèi)存分配;b、當(dāng)Eden區(qū)滿了,再創(chuàng)建對象,會因?yàn)樯暾埐坏娇臻g,觸發(fā)minorGC,進(jìn)行young(eden+1survivor)區(qū)的垃圾回收。(為什么是eden+1survivor:兩個survivor中始終有一個survivor是空的,空的那個被標(biāo)

17、記成To Survivor);c、minorGC時,Eden不能被回收的對象被放入到空的survivor(也就是放到To Survivor,同時Eden肯定會被清空),另一個survivor(From Survivor)里不能被GC回收的對象也會被放入這個survivor(To Survivor),始終保證一個survivor是空的。(MinorGC完成之后,To Survivor 和 From Survivor的標(biāo)記互換);d、當(dāng)做第3步的時候,如果發(fā)現(xiàn)存放對象的那個survivor滿了,則這些對象被copy到old區(qū),或者survivor區(qū)沒有滿,但是有些對象已經(jīng)足夠Old(通過XX:Ma

18、xTenuringThreshold參數(shù)來設(shè)置),也被放入Old區(qū)。(對象在Survivor區(qū)中每熬過一次Minor GC,年齡就增加1歲,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲)時,就會晉升到老年代中)(3)標(biāo)記-整理old space也可以標(biāo)記-復(fù)制策略嗎?當(dāng)然不行!young space中的對象大部分都是生命周期較短的對象,每次GC后,所剩下的活對象數(shù)量不是很大。而old space中的對象大部分都是生命周期特別長的對象,即使GC后,仍然會剩下大量的活對象。如果仍然采用復(fù)制動作,回收效率會變得非常低。根據(jù)old space的特點(diǎn),可以采用整理動作。整理時,先清除掉應(yīng)該清除的對象,然后把存

19、活對象“壓縮”到堆的一端,按順序排放。Old space(+Permanent Space)的垃圾回收是偶爾發(fā)生的,被稱為Full GC(主要回收)。Full GC因?yàn)樾枰獙φ麄€堆進(jìn)行回收,包括Young、Old和Perm,所以比Minor GC要慢,因此應(yīng)該盡可能減少Full GC的次數(shù)。在對JVM調(diào)優(yōu)的過程中,很大一部分工作就是對于FullGC的調(diào)節(jié)。有如下原因可能導(dǎo)致Full GC:· 年老代(Tenured)被寫滿· 持久代(Perm)被寫滿· System.gc()被顯示調(diào)用· 上一次GC之后Heap的各域分配策略動態(tài)變化4)、垃圾收集器垃圾收

20、集算法是內(nèi)存回收的理論基礎(chǔ),而垃圾收集器就是內(nèi)存回收的具體實(shí)現(xiàn)。堆(Heap)分代被目前大部分JVM所采用。它的核心思想是根據(jù)對象存活的生命周期將內(nèi)存劃分為若干個不同的區(qū)域。一般情況下將堆區(qū)劃分為old space和Young space,old space的特點(diǎn)是每次垃圾收集時只有少量對象需要被回收,而Young space的特點(diǎn)是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據(jù)不同代的特點(diǎn)采取最適合的收集算法。目前大部分垃圾收集器對于Young space都采取“標(biāo)記-復(fù)制”算法。而由于Old space的特點(diǎn)是每次回收都只回收少量對象,一般使用的是“標(biāo)記-整理”算法。(1)Youn

21、g Space上的GC實(shí)現(xiàn):Serial(串行): Serial收集器是最基本最古老的收集器,它是一個單線程收集器,并且在它進(jìn)行垃圾收集時,必須暫停所有用戶線程。Serial收集器是針對新生代的收集器,采用的是“標(biāo)記-復(fù)制”算法。它的優(yōu)點(diǎn)是實(shí)現(xiàn)簡單高效,但是缺點(diǎn)是會給用戶帶來停頓。這個收集器類型僅應(yīng)用于單核CPU桌面電腦。使用serial收集器會顯著降低應(yīng)用程序的性能。ParNew(并行): ParNew收集器是Serial收集器的多線程版本,使用多個線程進(jìn)行垃圾收集。Parallel Scavenge(并行): Parallel Scavenge收集器是一個新生

22、代的多線程收集器(并行收集器),它在回收期間不需要暫停其他用戶線程,其采用的是“標(biāo)記-復(fù)制”算法,該收集器與前兩個收集器有所不同,它主要是為了達(dá)到一個可控的吞吐量。(2)Old Space上的GC實(shí)現(xiàn):Serial Old(串行):Serial收集器的Old Space版本,采用的是“標(biāo)記-整理”算法。這個收集器類型僅應(yīng)用于單核CPU桌面電腦。使用serial收集器會顯著降低應(yīng)用程序的性能。Parallel Old(并行):Parallel Old是Parallel Scavenge收集器的Old Space版本(并行收集器),使用多線程和“標(biāo)記-整理”算法。CMS(并發(fā)):CMS(Curre

23、nt Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標(biāo)的收集器,它是一種并發(fā)收集器,采用的是"標(biāo)記-清除"算法。(3).G1G1(Garbage First)收集器是JDK1.7提供的一個新收集器,G1收集器基于“標(biāo)記-整理”算法實(shí)現(xiàn),也就是說不會產(chǎn)生內(nèi)存碎片。還有一個特點(diǎn)之前的收集器進(jìn)行收集的范圍都是整個新生代或老年代,而G1將整個Java堆(包括新生代,老年代)。3.JVM參數(shù)1).堆-Xmx:最大堆內(nèi)存,如:-Xmx512m-Xms:初始時堆內(nèi)存,如:-Xms256m-XX:MaxNewSize:最大年輕區(qū)內(nèi)存-XX:NewSize:初始時年輕區(qū)內(nèi)存.通

24、常為 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間。實(shí)際可用空間為 = Eden + 1 個 Survivor,即 90%-XX:MaxPermSize:最大持久帶內(nèi)存-XX:PermSize:初始時持久帶內(nèi)存-XX:+PrintGCDetails。打印 GC 信息 -XX:NewRatio 新生代與老年代的比例,如 XX:NewRatio=2,則新生代占整個堆空間的1/3,老年代占2/3 -XX:SurvivorRatio 新生代中 Eden 與 Survivor 的比值。默認(rèn)值為 8。即 Eden 占新生代

25、空間的 8/10,另外兩個 Survivor 各占 1/102).棧-xss:設(shè)置每個線程的堆棧大小. JDK1.5+ 每個線程堆棧大小為 1M,一般來說如果棧不是很深的話, 1M 是絕對夠用了的。3).垃圾回收4).JVM  client模式和server模式Java_home/bin/java命令有一個-server和-client參數(shù),該參數(shù)標(biāo)識了JVM以server模式或client模式啟動。JVM Server模式與client模式啟動,最主要的差別在于:-Server模式啟動時,速度較慢,但是一旦運(yùn)行起來后,性能將會有很大的提升。當(dāng)虛擬機(jī)運(yùn)行在-client模式

26、的時候,使用的是一個代號為C1的輕量級編譯器, 而-server模式啟動的虛擬機(jī)采用相對重量級,代號為C2的編譯器. C2比C1編譯器編譯的相對徹底,服務(wù)起來之后,性能更高。(1)查看當(dāng)前JVM默認(rèn)啟動模式j(luò)ava -version 可以直接查看出默認(rèn)使用的是client還是 server。(2)JVM默認(rèn)啟動模式自動偵測從JDK 5開始,如果沒有顯式地用-client或者-server參數(shù),那么JVM啟動時,會根據(jù)機(jī)器配置和JDK的版本,自動判斷該用哪種模式。· the definition of a server-class machine is one with at leas

27、t 2 CPUs and at least 2GB of physical memory.· windows平臺,64位版本的JDK,沒有提供-client模式,直接使用server模式。(3).通過配置文件,改變JVM啟動模式兩種模式的切換可以通過更改配置(jvm.cfg配置文件)來實(shí)現(xiàn):32位的JVM配置文件在JAVA_HOME/jre/lib/i386/jvm.cfg,64位的JVM配置文件在JAVA_HOME/jre/lib/amd64/jvm.cfg, 目前64位只支持server模式。例如:32位版本的JDK 5的jvm.cfg文件內(nèi)容:?123456-client

28、60;KNOWN-server KNOWN-hotspot ALIASED_TO -client-classic WARN-native ERROR-green ERROR64位版本的JDK 7的jvm.cfg文件內(nèi)容:?123456-server KNOWN-client IGNORE-hotspot ALIASED_TO -server-classic WARN-native ERROR-green ERROR4.堆 VS 棧JVM棧是運(yùn)行時的單位,而JVM堆是

29、存儲的單位。JVM棧代表了處理邏輯,而JVM堆代表了數(shù)據(jù)。JVM堆中存的是對象。JVM棧中存的是基本數(shù)據(jù)類型和JVM堆中對象的引用。JVM堆是所有線程共享,JVM棧是線程獨(dú)有。PS:Java中的參數(shù)傳遞是傳值呢?還是傳址?我們都知道:C 語言中函數(shù)參數(shù)的傳遞有:值傳遞,地址傳遞,引用傳遞這三種形式。但是在Java里,方法的參數(shù)傳遞方式只有一種:值傳遞。所謂值傳遞,就是將實(shí)際參數(shù)值的副本(復(fù)制品)傳入方法內(nèi),而參數(shù)本身不會受到任何影響。要說明這個問題,先要明確兩點(diǎn):1.引用在Java中是一種數(shù)據(jù)類型,跟基本類型int等等同一地位。2.程序運(yùn)行永遠(yuǎn)都是在JVM棧中進(jìn)行的,因而參數(shù)傳遞時,只存在傳遞基本類型和對象引用的問題。不會直接傳對象本身。在運(yùn)行JVM棧中,基本類型和引用的處理是一樣的,都是傳值。如果是傳引用的方法調(diào)用,可以理解為“傳引用值”的傳值調(diào)用,即“引用值”被做了一個復(fù)制品,然后賦值給參數(shù),引用的處理跟基本類型是完全一樣的。但是當(dāng)進(jìn)入被調(diào)用方法時,被傳遞的這個引用值,被程序解釋(或者查找)到JVM堆中的對象,這個時候才對應(yīng)到真正的對象。如果此時進(jìn)行修改,修改的是引用對應(yīng)的對象,而不是引用本身,即:修改的是JVM堆中的數(shù)據(jù)。所以這個修改是可以保持的了。例如:?12345678910111213141516171

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論