JVM體系結(jié)構(gòu)

內(nèi)存溢出和內(nèi)存泄漏的區(qū)別

內(nèi)存溢出?:out of memory,是指程序在申請內(nèi)存時,沒有足夠的內(nèi)存空間供其使用阅签,出現(xiàn)out of memory。比方說棧枕面,棧滿時再做進棧必定產(chǎn)生空間溢出愿卒,叫上溢,棾泵兀空時再做退棧也產(chǎn)生空間溢出掘猿,稱為下溢。就是分配的內(nèi)存不足以放下數(shù)據(jù)項序列,稱為內(nèi)存溢出唇跨。

內(nèi)存泄露?:memory leak稠通,是指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間买猖,一次內(nèi)存泄露危害可以忽略改橘,但內(nèi)存泄露堆積后果很嚴(yán)重,無論多少內(nèi)存,遲早會被占光玉控。向系統(tǒng)申請分配內(nèi)存進行使用(new)飞主,可是使用完了以后卻不歸還(delete),結(jié)果你申請到的那塊內(nèi)存你自己也不能再訪問(也許你把它的地址給弄丟了)高诺,而系統(tǒng)也不能再次將它分配給需要的程序碌识。

Java虛擬機的體系結(jié)構(gòu)和運行時數(shù)據(jù)區(qū)域

?一個JVM實例的行為不光是它自己的事,還涉及到它的子系統(tǒng)虱而、存儲區(qū)域筏餐、數(shù)據(jù)類型和指令這些部分,它們描述了JVM的一個抽象的內(nèi)部體系結(jié)構(gòu)牡拇,其目的不光規(guī)定實現(xiàn)JVM時它內(nèi)部的體系結(jié)構(gòu)魁瞪,更重要的是提供了一種方式,用于嚴(yán)格定義實現(xiàn)時的外部行為惠呼。每個JVM都有兩種機制导俘,一個是裝載具有合適名稱的類(類或是接口),叫做類裝載子系統(tǒng)剔蹋;另外的一個負(fù)責(zé)執(zhí)行包含在已裝載的類或接口中的指令旅薄,叫做運行引擎。每個JVM又包括方法區(qū)泣崩、堆少梁、Java棧、程序計數(shù)器和本地方法棧這五個部分律想,這幾個部分和類裝載機制與運行引擎機制一起組成的體系結(jié)構(gòu)圖為:

Java虛擬機定義了若干種程序運行期間會使用到的運行時數(shù)據(jù)區(qū)猎莲,其中有一些會隨著虛擬機啟動而創(chuàng)建,隨著虛擬機退出而銷毀技即。另外一些則是與線程一一對應(yīng)的著洼,這些與線程對應(yīng)的數(shù)據(jù)區(qū)域會隨著線程開始和結(jié)束而創(chuàng)建和銷毀

Java虛擬機的運行時數(shù)據(jù)區(qū)包括了:方法區(qū)、Java堆、Java虛擬機棧身笤、PC寄存器豹悬、本地方法棧,還有常量池液荸。它們被分為兩大類-------線程共享瞻佛、私有數(shù)據(jù)區(qū)。

1.線程共享數(shù)據(jù)區(qū)

包括:Java堆娇钱、方法區(qū)伤柄、常量池。它們會隨著虛擬機啟動而創(chuàng)建文搂,隨著虛擬機退出而銷毀适刀。

堆:

java堆在虛擬機啟動的時候被創(chuàng)建,Java堆主要用來為類實例對象和數(shù)組分配內(nèi)存煤蹭。Java虛擬機規(guī)范并沒有規(guī)定對象在堆中的形式笔喉。對于大多數(shù)應(yīng)用來說,Java堆(Java Heap)是Java虛擬機所管理的內(nèi)存中最大的一塊硝皂。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域常挚,在虛擬機啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象實例稽物,幾乎所有的對象實例都在這里分配內(nèi)存奄毡。這一點在Java虛擬機規(guī)范中的描述是:所有的對象實例以及數(shù)組都要在堆上分配,但是隨著JIT(Just In Time)編譯器的發(fā)展與逃逸分析技術(shù)的逐漸成熟姨裸,棧上分配秧倾、標(biāo)量替換優(yōu)化技術(shù)將會導(dǎo)致一些微妙的變化發(fā)生,所有的對象都分配在堆上也漸漸變得不是那么“絕對”了-----可是使用逃逸分析和棧幀存儲技術(shù)傀缩。

? ? ? ? 如果從內(nèi)存分配的角度看,線程共享的Java堆中可能劃分出多個線程私有的分配緩沖區(qū)(Thread Local Allocation Buffer农猬,TLAB)赡艰。不過,無論如何劃分斤葱,都與存放內(nèi)容無關(guān)慷垮,無論哪個區(qū)域,存儲的都仍然是對象實例揍堕,進一步劃分的目的是為了更好地回收內(nèi)存料身,或者更快地分配內(nèi)存。

? ? ? ? 參考《Java虛擬機規(guī)范(第7版)》的描述衩茸,Java堆可以處于物理上不連續(xù)的內(nèi)存空間中芹血,只要邏輯上是連續(xù)的即可,就像我們的磁盤空間一樣。在實現(xiàn)時幔烛,既可以實現(xiàn)成固定大小的啃擦,也可以是可擴展的,不過當(dāng)前主流的虛擬機都是按照可擴展來實現(xiàn)的(通過-Xmx和-Xms控制)饿悬。

在 Java 中令蛉,堆被劃分成兩個不同的區(qū)域:新生代 ( Young )、老年代 ( Old )狡恬;這也就是JVM采用的“分代收集算法”珠叔,簡單說,就是針對不同特征的java對象采用不同的策略實施存放和回收弟劲,自然所用分配機制和回收算法就不一樣祷安。新生代 ( Young ) 又被劃分為三個區(qū)域:Eden、From Survivor函卒、To?Survivor辆憔。

? ? ? ??分代收集算法:采用不同算法處理[存放和回收]Java瞬時對象和長久對象。大部分Java對象都是瞬時對象报嵌,朝生夕滅虱咧,存活很短暫,通常存放在Young新生代锚国,采用復(fù)制算法對新生代進行垃圾回收腕巡。老年代對象的生命周期一般都比較長,極端情況下會和JVM生命周期保持一致血筑;通常采用標(biāo)記-壓縮算法對老年代進行垃圾回收绘沉。

方法區(qū):

方法區(qū)在虛擬機啟動的時候被創(chuàng)建,它存儲了每一個類的結(jié)構(gòu)信息豺总,例如運行時常量池车伞、字段和方法數(shù)據(jù)、構(gòu)造函數(shù)和普通方法的字節(jié)碼內(nèi)容喻喳、還包括在類另玖、實例、接口初始化時用到的特殊方法表伦。?

方法區(qū)(Method Area)與Java堆一樣谦去,是各個線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬機加載的類信息蹦哼、常量鳄哭、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)纲熏。雖然Java虛擬機規(guī)范把方法區(qū)描述為堆的一個邏輯部分妆丘,但是它卻有一個別名叫做Non-Heap(非堆)锄俄,目的應(yīng)該是與Java堆區(qū)分開來。

對于習(xí)慣在HotSpot虛擬機上開發(fā)和部署程序的開發(fā)者來說飘痛,很多人愿意把方法區(qū)稱為“永久代”(Permanent Generation)珊膜,本質(zhì)上兩者并不等價,僅僅是因為HotSpot虛擬機的設(shè)計團隊選擇把GC分代收集擴展至方法區(qū)宣脉,或者說使用永久代來實現(xiàn)方法區(qū)而已车柠。對于其他虛擬機(如BEA JRockit、IBM J9等)來說是不存在永久代的概念的塑猖。即使是HotSpot虛擬機本身竹祷,根據(jù)官方發(fā)布的路線圖信息,現(xiàn)在也有放棄永久代并“搬家”至Native Memory來實現(xiàn)方法區(qū)的規(guī)劃了羊苟。

?Java虛擬機規(guī)范對這個區(qū)域的限制非常寬松塑陵,除了和Java堆一樣不需要連續(xù)的內(nèi)存和可以選擇固定大小或者可擴展外,還可以選擇不實現(xiàn)垃圾收集蜡励。相對而言令花,垃圾收集行為在這個區(qū)域是比較少出現(xiàn)的,但并非數(shù)據(jù)進入了方法區(qū)就如永久代的名字一樣“永久”存在了凉倚。這個區(qū)域的內(nèi)存回收目標(biāo)主要是針對常量池的回收和對類型的卸載兼都,一般來說這個區(qū)域的回收“成績”比較難以令人滿意,尤其是類型的卸載稽寒,條件相當(dāng)苛刻扮碧,但是這部分區(qū)域的回收確實是有必要的。在Sun公司的BUG列表中杏糙,曾出現(xiàn)過的若干個嚴(yán)重的BUG就是由于低版本的HotSpot虛擬機對此區(qū)域未完全回收而導(dǎo)致內(nèi)存泄漏慎王。

方法區(qū)可能發(fā)生如下異常情況:?如果方法區(qū)的內(nèi)存空間不能滿足內(nèi)存分配請求,那Java虛擬機將拋出一個OutOfMemoryError異常.?

常量池:

運行時常量池(Runtime Constant Pool)是每一個類或接口的常量池的運行時表示形式宏侍,它包括了若干種不同的常量:從編譯期可知的數(shù)值字面量到必須運行期解析后才能獲得的方法或字段引用赖淤。運行時常量池在方法區(qū)中揖庄。

? ? ? ??運行時常量池(Runtime Constant Pool)是方法區(qū)的一部分暴心。Class文件中除了有類的版本劲赠、字段锅睛、方法、接口等描述等信息外悲龟,還有一項信息是常量池(Constant Pool Table),用于存放編譯期生成的各種字面量和符號引用,這部分內(nèi)容將在類加載后存放到方法區(qū)的運行時常量池中锨天。Java虛擬機對Class文件的每一部分(自然也包括常量池)的格式都有嚴(yán)格的規(guī)定,每一個字節(jié)用于存儲哪種數(shù)據(jù)都必須符合規(guī)范上的要求剃毒,這樣才會被虛擬機認(rèn)可病袄、裝載和執(zhí)行搂赋。但對于運行時常量池,Java虛擬機規(guī)范沒有做任何細(xì)節(jié)的要求益缠,不同的提供商實現(xiàn)的虛擬機可以按照自己的需要來實現(xiàn)這個內(nèi)存區(qū)域脑奠。不過,一般來說幅慌,除了保存Class文件中描述的符號引用外宋欺,還會把翻譯出來的直接引用也存儲在運行時常量池中。 運行時常量池相對于Class文件常量池的另外一個重要特征是具備動態(tài)性胰伍,Java語言并不要求常量一定只能在編譯期產(chǎn)生齿诞,也就是并非預(yù)置入Class文件中常量池的內(nèi)容才能進入方法區(qū)運行時常量池,運行期間也可能將新的常量放入池中骂租,這種特性被開發(fā)人員利用得比較多的便是String類的intern()方法祷杈。 既然運行時常量池是方法區(qū)的一部分自然會受到方法區(qū)內(nèi)存的限制,當(dāng)常量池?zé)o法再申請到內(nèi)存時會拋出OutOfMemoryError異常渗饮。

? ? ? ??在創(chuàng)建類和接口的運行時常量池時但汞,可能會發(fā)生如下異常情況:當(dāng)創(chuàng)建類或接口的時候,如果構(gòu)造運行時常量池所需要的內(nèi)存空間超過了方法區(qū)所能提供的最大值互站,那Java虛擬機將會拋出一個OutOfMemoryError異常私蕾。

線程私有數(shù)據(jù)區(qū)

包括:PC寄存器、JVM棧云茸、本地方法區(qū)是目。它們是與線程一一對應(yīng)的,這些與線程對應(yīng)的數(shù)據(jù)區(qū)域會隨著線程開始和結(jié)束而創(chuàng)建和銷毀标捺。

(1)PC寄存器

? ? ? ? PC(Program Counter Register)是一塊較小的內(nèi)存空間懊纳,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。在虛擬機的概念模型里(僅是概念模型亡容,各種虛擬機可能會通過一些更高效的方式去實現(xiàn))嗤疯,字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支闺兢、循環(huán)茂缚、跳轉(zhuǎn)、異常處理屋谭、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成脚囊。

每個Java虛擬機線程都有自己的PC寄存器。在某個線程被新建時桐磁,會獲得一個PC寄存器悔耘。線程當(dāng)前執(zhí)行的方法稱為當(dāng)前方法,PC寄存器用來存放當(dāng)前方法中當(dāng)前執(zhí)行的字節(jié)碼指令的地址我擂;之所以為每一個線程都分配一個PC寄存器衬以,試想:多線程運行時缓艳,某個時間片內(nèi)只執(zhí)行一個線程,CPU在不停的切換多個線程看峻,那如何記錄具體每一個線程上一次執(zhí)行到哪個位置了呢阶淘,這時候PC寄存器用來存放當(dāng)前方法中當(dāng)前執(zhí)行的字節(jié)碼指令的地址,就完美解決了互妓,這就是為什么PC寄存器是線程私有數(shù)據(jù)區(qū)的原因溪窒。

如果當(dāng)前方法是本地方法(Native),那么寄存器存放undefined车猬。寄存器的大小至少應(yīng)該能夠存放一個returnAddress類型的數(shù)據(jù)或者與平臺相關(guān)的本地指針的值霉猛。

PC寄存器是惟一一個沒有明確規(guī)定需要拋出OutOfMemoryError異常的運行時數(shù)據(jù)區(qū)。

(2)JVM棧

每個Java虛擬機線程都有自己的Java虛擬機棧珠闰。Java虛擬機棧用來存放棧幀惜浅,而棧幀主要包括了:局部變量表、操作數(shù)棧伏嗜、動態(tài)鏈接坛悉。Java虛擬機棧允許被實現(xiàn)為固定大小或者可動態(tài)擴展的內(nèi)存大小。

? ? ? ??與程序一樣承绸,Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的裸影,它的生命周期計數(shù)器與線程相同。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會同時創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表军熏、操作棧轩猩、動態(tài)鏈接、方法出口等信息荡澎。每一個方法被調(diào)用直至執(zhí)行完成的過程均践,就對應(yīng)著一個棧幀在虛擬機棧中從入棧到出棧的過程。

經(jīng)常有人把Java內(nèi)存區(qū)分為堆內(nèi)存(Heap)和棧內(nèi)存(Stack)摩幔,這種分法比較粗糙彤委,Java內(nèi)存區(qū)域的劃分實際上遠(yuǎn)比這復(fù)雜。這種劃分方式的流行只能說明大多數(shù)程序員最關(guān)注的或衡、與對象內(nèi)存分配關(guān)系最密切的內(nèi)存區(qū)域是這兩塊焦影。其中所指的“堆”在后面會專門講述,而所指的“椃舛希”就是現(xiàn)在講的虛擬機棧斯辰,或者說是虛擬機棧中的局部變量表部分。

Java虛擬機使用局部變量表來完成方法調(diào)用時的參數(shù)傳遞坡疼。局部變量表的長度在編譯期已經(jīng)決定了并存儲于類和接口的二進制表示中椒涯,一個局部變量可以保存一個類型為boolean、byte回梧、char废岂、short、float狱意、reference?和?returnAddress的數(shù)據(jù)湖苞,兩個局部變量可以保存一個類型為long和double的數(shù)據(jù)。

Java虛擬機提供一些字節(jié)碼指令來從局部變量表或者對象實例的字段中復(fù)制常量或變量值到操作數(shù)棧中详囤,也提供了一些指令用于從操作數(shù)棧取走數(shù)據(jù)财骨、操作數(shù)據(jù)和把操作結(jié)果重新入棧。在方法調(diào)用的時候藏姐,操作數(shù)棧也用來準(zhǔn)備調(diào)用方法的參數(shù)以及接收方法返回結(jié)果隆箩。

每個棧幀中都包含一個指向運行時常量區(qū)的引用支持當(dāng)前方法的動態(tài)鏈接。在Class文件中羔杨,方法調(diào)用和訪問成員變量都是通過符號引用來表示的捌臊,動態(tài)鏈接的作用就是將符號引用轉(zhuǎn)化為實際方法的直接引用或者訪問變量的運行是內(nèi)存位置的正確偏移量。?

總的來說兜材,Java虛擬機棧是用來存放局部變量和過程結(jié)果的地方理澎。?

Java虛擬機棧可能發(fā)生如下異常情況:?如果Java虛擬機棧被實現(xiàn)為固定大小內(nèi)存曙寡,線程請求分配的棧容量超過Java虛擬機棧允許的最大容量時糠爬,Java虛擬機將會拋出一個StackOverflowError異常。?

如果Java虛擬機棧被實現(xiàn)為動態(tài)擴展內(nèi)存大小举庶,并且擴展的動作已經(jīng)嘗試過执隧,但是目前無法申請到足夠的內(nèi)存去完成擴展,或者在建立新的線程時沒有足夠的內(nèi)存去創(chuàng)建對應(yīng)的虛擬機棧户侥,那Java虛擬機將會拋出一個OutOfMemoryError異常镀琉。?

(3)本地方法區(qū)

? ? ? ?本地方法棧用于支持native方法的運行。(native方法添祸,比如用C/C++實現(xiàn)的代碼)滚粟。

? ? ??本地方法棧(Native Method Stacks)與虛擬機棧所發(fā)揮的作用是非常相似的,其區(qū)別不過是虛擬機棧為虛擬機執(zhí)行Java方法(也就是字節(jié)碼)服務(wù)刃泌,而本地方法棧則是為虛擬機使用到的Native方法服務(wù)凡壤。虛擬機規(guī)范中對本地方法棧中的方法使用的語言、使用方式與數(shù)據(jù)結(jié)構(gòu)并沒有強制規(guī)定耙替,因此具體的虛擬機可以自由實現(xiàn)它亚侠。甚至有的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二為一。與虛擬機棧一樣俗扇,本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError異常硝烂。

堆和GC

?Java 中的堆是 JVM 所管理的最大的一塊內(nèi)存空間,主要用于存放各種類的實例對象和數(shù)組铜幽。它的管理是由垃圾回收器(GC)來負(fù)責(zé)的滞谢;不給程序員顯式釋放對象的能力串稀。Java不規(guī)定具體使用的垃圾回收算法,可以根據(jù)系統(tǒng)的需求使用各種各樣的算法。Java的堆區(qū)狮杨,可以是不連續(xù)的母截。

在 Java 中,堆被劃分成兩個不同的區(qū)域:新生代 ( Young )橄教、老年代 ( Old )清寇;這也就是JVM采用的“分代收集算法”,簡單說护蝶,就是針對不同特征的java對象采用不同的策略實施存放和回收华烟,自然所用分配機制和回收算法就不一樣。新生代 ( Young ) 又被劃分為三個區(qū)域:Eden持灰、From Survivor盔夜、To?Survivor。?

分代收集算法:采用不同算法處理[存放和回收]Java瞬時對象和長久對象搅方。大部分Java對象都是瞬時對象比吭,朝生夕滅,存活很短暫姨涡,通常存放在Young新生代衩藤,采用復(fù)制算法對新生代進行垃圾回收。老年代對象的生命周期一般都比較長涛漂,極端情況下會和JVM生命周期保持一致赏表;通常采用標(biāo)記-壓縮算法對老年代進行垃圾回收。這樣劃分的目的是為了使 JVM 能夠更好的管理堆內(nèi)存中的對象匈仗,包括內(nèi)存的分配以及回收瓢剿。

堆的內(nèi)存模型大致為下圖:

? ? ? ? ? 從圖中可以看出:?堆大小 = 新生代 + 老年代。其中悠轩,堆的大小可以通過參數(shù) –Xms间狂、-Xmx 來指定。

? ? ? ? ? 默認(rèn)的火架,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數(shù) –XX:NewRatio 來指定 )鉴象,即:新生代 ( Young ) = 1/3 的堆空間大小。

? ? ? ? ? 老年代 ( Old ) = 2/3 的堆空間大小何鸡。其中纺弊,新生代 ( Young ) 被細(xì)分為 Eden 和 兩個 Survivor 區(qū)域,這兩個 Survivor 區(qū)域分別被命名為 from 和 to骡男,以示區(qū)分淆游。

默認(rèn)的----Edem : from : to = 8 : 1 : 1 ( 可以通過參數(shù) –XX:SurvivorRatio 來設(shè)定 )。

JVM 每次只會使用 Eden 和其中的一塊 Survivor 區(qū)域來為對象服務(wù),所以無論什么時候犹菱,總是有一塊 Survivor 區(qū)域是空閑著的拾稳。

因此,新生代實際可用的內(nèi)存空間為 9/10 ( 即90% )的新生代空間已亥。

GC堆:

(1)Java 中的堆也是 GC 收集垃圾的主要區(qū)域熊赖。GC 分為兩種:Minor GC(新生代回收算法)、Full GC ( 老年代的回收算法虑椎,或稱為 Major GC )。

(2)Minor GC 是發(fā)生在新生代中的垃圾收集動作俱笛,所采用的是復(fù)制算法捆姜。

新生代幾乎是所有 Java 對象出生的地方,即 Java 對象申請的內(nèi)存以及存放都是在這個地方迎膜。Java 中的大部分對象通常不需長久存活泥技,具有朝生夕滅的性質(zhì)。

(3)當(dāng)一個對象被判定為 "死亡" 的時候磕仅,GC 就有責(zé)任來回收掉這部分對象的內(nèi)存空間珊豹。新生代是 GC 收集垃圾的頻繁區(qū)域。

(4)當(dāng)對象在 Eden ( 包括一個 Survivor 區(qū)域榕订,這里假設(shè)是 from 區(qū)域 ) 出生后店茶,在經(jīng)過一次 Minor GC 后,如果對象還存活劫恒,并且能夠被另外一塊 Survivor 區(qū)域所容納

( 上面已經(jīng)假設(shè)為 from 區(qū)域贩幻,這里應(yīng)為 to 區(qū)域,即 to 區(qū)域有足夠的內(nèi)存空間來存儲 Eden 和 from 區(qū)域中存活的對象 )两嘴,則使用復(fù)制算法將這些仍然還存活的對象復(fù)制到另外一塊 Survivor 區(qū)域 ( 即 to 區(qū)域 ) 中丛楚,然后清理所使用過的 Eden 以及 Survivor 區(qū)域 ( 即 from 區(qū)域 ),并且將這些對象的年齡設(shè)置為1憔辫,以后對象在 Survivor 區(qū)每熬過一次 Minor GC趣些,就將對象的年齡 + 1,當(dāng)對象的年齡達(dá)到某個值時 ( 默認(rèn)是 15 歲贰您,可以通過參數(shù) -XX:MaxTenuringThreshold 來設(shè)定 )坏平,這些對象就會成為老年代。

但這也不是一定的枉圃,對于一些較大的對象 ( 即需要分配一塊較大的連續(xù)內(nèi)存空間 ) 則是直接進入到老年代功茴。

(5)Full GC 是發(fā)生在老年代的垃圾收集動作,所采用的是標(biāo)記-清除算法孽亲。

(6)現(xiàn)實的生活中坎穿,老年代的人通常會比新生代的人 "早死"。堆內(nèi)存中的老年代(Old)不同于這個,老年代里面的對象幾乎個個都是在 Survivor 區(qū)域中熬過來的玲昧,它們是不會那么容易就 "死掉" 了的栖茉。因此,F(xiàn)ull GC 發(fā)生的次數(shù)不會有 Minor GC 那么頻繁孵延,并且做一次 Full GC 要比進行一次 Minor GC 的時間更長吕漂。

(7)另外,標(biāo)記-清除算法收集垃圾的時候會產(chǎn)生許多的內(nèi)存碎片 ( 即不連續(xù)的內(nèi)存空間 )尘应,此后需要為較大的對象分配內(nèi)存空間時惶凝,若無法找到足夠的連續(xù)的內(nèi)存空間,就會提前觸發(fā)一次 GC 的收集動作犬钢。

設(shè)置 JVM 參數(shù)為 -XX:+PrintGCDetails苍鲜,使得控制臺能夠顯示 GC 相關(guān)的日志信息,執(zhí)行上面代碼玷犹,下面是其中一次執(zhí)行的結(jié)果混滔。

jvm 可配置的參數(shù)選項可以參考 Oracle 官方網(wǎng)站給出的相關(guān)信息:

下面只列舉其中的幾個常用和容易掌握的配置選項:

?-Xms?初始堆大小。如:-Xms256m

?-Xmx?最大堆大小歹颓。如:-Xmx512m

?-Xmn?新生代大小坯屿。通常為 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間巍扛。實際可用空間為 = Eden + 1 個 Survivor领跛,即 90% ?

?-Xss?JDK1.5+ 每個線程堆棧大小為 1M,一般來說如果棧不是很深的話电湘, 1M 是絕對夠用了的隔节。

?-XX:NewRatio?新生代與老年代的比例,如 –XX:NewRatio=2寂呛,則新生代占整個堆空間的1/3怎诫,老年代占2/3

?-XX:SurvivorRatio?新生代中 Eden 與 Survivor 的比值。默認(rèn)值為 8贷痪。即 Eden 占新生代空間的 8/10幻妓,另外兩個 Survivor 各占 1/10 ?

?-XX:PermSize?永久代(方法區(qū))的初始大小

?-XX:MaxPermSize?永久代(方法區(qū))的最大值

?-XX:+PrintGCDetails?打印 GC 具體細(xì)節(jié)信息

?-XX:+HeapDumpOnOutOfMemoryError?讓虛擬機在發(fā)生內(nèi)存溢出時 Dump 出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲快照,以便分析用

JVM運行時數(shù)據(jù)區(qū)域及GC


直接內(nèi)存(Direct Memory):

直接內(nèi)存(DirectMemory)并不是虛擬機運行時數(shù)據(jù)區(qū)的一部分劫拢,也不是Java虛擬機規(guī)范中定義的內(nèi)存區(qū)域肉津,但是這部分內(nèi)存也被頻繁地使用,而且也可能導(dǎo)致OutOfMemoryError異常出現(xiàn)舱沧。JDK1.4加的NIO中妹沙,ByteBuffer有個方法是allocateDirect(intcapacity) ,這是一種基于通道(Channel)與緩沖區(qū)(Buffer)的I/O方式熟吏,它可以使用Native函數(shù)庫直接分配堆外內(nèi)存距糖,然后通過一個存儲在Java堆里面的DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作玄窝。這樣能在一些場景中顯著提高性能,因為避免了在Java堆和Native堆中來回復(fù)制數(shù)據(jù)悍引。顯然恩脂,本機直接內(nèi)存的分配不會受到Java堆大小的限制,但是趣斤,既然是內(nèi)存俩块,則肯定還是會受到本機總內(nèi)存(包括RAM及SWAP區(qū)或者分頁文件)的大小及處理器尋址空間的限制。服務(wù)器管理員配置虛擬機參數(shù)時浓领,一般會根據(jù)實際內(nèi)存設(shè)置-Xmx等參數(shù)信息玉凯,但經(jīng)常會忽略掉直接內(nèi)存,使得各個內(nèi)存區(qū)域的總和大于物理內(nèi)存限制(包括物理上的和操作系統(tǒng)級的限制)联贩,從而導(dǎo)致動態(tài)擴展時出現(xiàn)OutOfMemoryError異常壮啊。

JVM棧

是運行時的單位,而JVM堆是存儲的單位撑蒜。JVM棧解決程序的運行問題,即程序如何執(zhí)行玄渗,或者說如何處理數(shù)據(jù);JVM堆解決的是數(shù)據(jù)存儲的問題座菠,即數(shù)據(jù)怎么放、放在哪兒藤树。在Java中一個線程就會相應(yīng)有一個線程JVM棧與之對應(yīng)浴滴,這點很容易理解,因為不同的線程執(zhí)行邏輯有所不同岁钓,因此需要一個獨立的線程JVM棧升略。而JVM堆則是所有線程共享的。JVM棧因為是運行單位屡限,因此里面存儲的信息都是跟當(dāng)前線程(或程序)相關(guān)信息的品嚣。包括局部變量、程序運行狀態(tài)钧大、方法返回值等等;而JVM堆只負(fù)責(zé)存儲對象信息翰撑。

JVM棧的組成元素——棧幀

棧幀由三部分組成:局部變量區(qū)、操作數(shù)棧啊央、幀數(shù)據(jù)區(qū)眶诈。局部變量區(qū)和操作數(shù)棧的大小要視對應(yīng)的方法而定,他們是按字長計算的瓜饥。但調(diào)用一個方法時逝撬,它從類型信息中得到此方法局部變量區(qū)和操作數(shù)棧大小,并據(jù)此分配棧內(nèi)存乓土,然后壓入JVM棧宪潮。

局部變量區(qū):局部變量區(qū)被組織為以一個字長為單位溯警、從0開始計數(shù)的數(shù)組,類型為short坎炼、byte和char的值在存入數(shù)組前要被轉(zhuǎn)換成int值愧膀,而long和double在數(shù)組中占據(jù)連續(xù)的兩項,在訪問局部變量中的long或double時谣光,只需取出連續(xù)兩項的第一項的索引值即可,如某個long值在局部變量區(qū)中占據(jù)的索引是3檩淋、4項,取值時萄金,指令只需取索引為3的long值即可蟀悦。

操作數(shù)棧和局部變量區(qū)一樣,操作數(shù)棧也被組織成一個以字長為單位的數(shù)組氧敢。但和前者不同的是日戈,它不是通過索引來訪問的,而是通過入棧和出棧來訪問的孙乖≌懔叮可把操作數(shù)棧理解為存儲計算時,臨時數(shù)據(jù)的存儲區(qū)域唯袄。

JVM堆

在 Java 中弯屈,堆被劃分成兩個不同的區(qū)域:新生代 ( Young )、老年代 ( Old )恋拷。新生代 ( Young ) 又被劃分為三個區(qū)域:Eden资厉、From Survivor、To?Survivor蔬顾。這樣劃分的目的是為了使 JVM 能夠更好的管理堆內(nèi)存中的對象宴偿,包括內(nèi)存的分配以及回收。堆的內(nèi)存模型大致為:

從圖中可以看出:?堆大小 = 新生代 + 老年代诀豁。其中窄刘,堆的大小可以通過參數(shù) –Xms、-Xmx 來指定且叁。本人使用的是 JDK1.7都哭,以下涉及的 JVM 默認(rèn)值均以該版本為準(zhǔn)。默認(rèn)的逞带,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數(shù) –XX:NewRatio 來指定 )欺矫,即:新生代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小展氓。其中穆趴,新生代 ( Young ) 被細(xì)分為 Eden 和 兩個 Survivor 區(qū)域,這兩個 Survivor 區(qū)域分別被命名為 from 和 to遇汞,以示區(qū)分未妹。默認(rèn)的簿废,Eden : from : to = 8 : 1 : 1 ( 可以通過參數(shù) –XX:SurvivorRatio 來設(shè)定 ),即:?Eden = 8/10 的新生代空間大小络它,from = to = 1/10 的新生代空間大小族檬。JVM 每次只會使用 Eden 和其中的一塊 Survivor 區(qū)域來為對象服務(wù),所以無論什么時候化戳,總是有一塊 Survivor 區(qū)域是空閑著的单料。因此,新生代實際可用的內(nèi)存空間為 9/10 ( 即90% )的新生代空間点楼。

GC收集算法

在HotSpot中采用可達(dá)性分析方法(Reachability Analysis)判斷一個對象是否可以被垃圾回收扫尖,這個算法的基本思想是通過一系列的稱謂”GC Roots”的對象作為起始點,從這些節(jié)點開始向下搜索掠廓,搜索所有走過的路徑稱為引用鏈换怖,當(dāng)一個對象到GC Roots沒有任何引用鏈相連,則說明該對象是不可用的蟀瞧,如下圖所示:

在Java語言中沉颂,可作為GC Roots的對象包括下面幾種:

虛擬機棧(棧中的本地變量表)中引用的對象。

方法區(qū)中類靜態(tài)屬性引用的對象

方法區(qū)中常量引用的對象

本地方法棧中JNI(即Native方法)引用的對象

4種對象引用類型

在JDK1.2之后悦污,Java對引用的概念進行的擴充兆览,將引用分為強引用(Strong Reference)、軟應(yīng)用(Soft Reference)塞关、弱引用(Weak Reference)、虛引用(Phantom Reference)子巾,這4中引用強度依次逐漸減弱:

?強引用(Strong Reference):使用new 這個關(guān)鍵字創(chuàng)建對象時被創(chuàng)建的對象就是強引用帆赢,如Object object = new Object() 這個object就是一個強引用,只要強引用還存在线梗,垃圾收集器永遠(yuǎn)不會回收掉被引用對象椰于。?

軟應(yīng)用(Soft Reference):軟引用用來描述那些還有用但并非必須的對象,對于軟引用關(guān)聯(lián)的對象仪搔,在系統(tǒng)即將發(fā)生內(nèi)存溢出異常之前瘾婿,將會把這些對象列進回收范圍之中進行第二次回收。如果這次回收還沒有足夠內(nèi)存時烤咧,才會拋出內(nèi)存溢出異常偏陪。

弱引用(Weak Reference):也是用來描述非必須的對象,但是它的強度比軟引用更弱一些煮嫌,被引用關(guān)聯(lián)的對象只能生存到下一次垃圾收集發(fā)生之前笛谦。當(dāng)垃圾收集器工作時,無論當(dāng)前內(nèi)存是否足夠昌阿,都會回收掉弱引用關(guān)聯(lián)的對象饥脑。

虛引用(Phantom Reference):它是最弱的一種引用關(guān)系恳邀,對象是否有虛引用不會影響其生命周期,虛引用的唯一目的就是能在這個對象被回收時收到一個系統(tǒng)通知灶轰。

finalize()方法

?????? 對象在被回收之前要經(jīng)歷兩次標(biāo)記過程谣沸,如果發(fā)現(xiàn)對象經(jīng)可達(dá)性分析檢測,沒有引用關(guān)聯(lián)笋颤,它將會被標(biāo)記并且進行篩選乳附,篩選條件是此對象是否有必要執(zhí)行finalize()方法,當(dāng)對象沒有覆蓋finalize()方法或finalize()方法已被虛擬機調(diào)用過椰弊,虛擬機認(rèn)為這兩種情況均為沒有必要執(zhí)行许溅,對象將被回收,反之先執(zhí)行finalize()后秉版,收集對象贤重,JVM并不保證finalize()一定成功被執(zhí)行。

內(nèi)存清理算法思想

標(biāo)記-清除算法:標(biāo)記-清除(Mark-Sweep)算法是最基礎(chǔ)的算法清焕,就如它的名字一樣并蝗,算法分為”標(biāo)記”和”清除”兩個階段:首先標(biāo)記出所有需要回收的對象,在標(biāo)記完成后統(tǒng)一回收掉所有被標(biāo)記的對象秸妥。之所以說它是最基礎(chǔ)的收集算法滚停,是因為后續(xù)的收集算法都是基于這種思路并對其缺點進行改進而得到的。它主要有兩個缺點:一個是效率問題粥惧,標(biāo)記和清除過程的效率都不高键畴;另外一個是空間問題,標(biāo)記清楚后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片突雪,空間碎片太多可能會導(dǎo)致起惕,當(dāng)程序在以后的運行過程中需要分配較大對象時無法找到足夠連續(xù)的內(nèi)存空間而不得不提前出發(fā)另一次垃圾收集動作。

標(biāo)記-整理算法:根據(jù)老年代的特點咏删,有人提出了另外一種”標(biāo)記-整理”算法惹想,標(biāo)記過程仍然與標(biāo)記-清楚算法一樣,但是后續(xù)步驟不是直接對可回收對象進行清理督函,而是讓所有存活的對象都向一端移動嘀粱,然后直接清理掉端邊界意外的內(nèi)存。

分代收集算法:當(dāng)前商業(yè)虛擬機的垃圾收集都采用分代收集(Generational?Collection)算法辰狡,這種算法并沒有什么新的思想锋叨,只是根據(jù)對象的存活周期的不同將內(nèi)存劃分為幾塊。一般是把Java堆分成新生代和老年代宛篇,這樣就可以根據(jù)各個年代的特點采用最適當(dāng)?shù)氖占惴ūT谛律校看卫占瘯r都發(fā)現(xiàn)有大批對象死去些己,只有少量存活豌鸡,那么就選用復(fù)制算法嘿般,只需要付出少量存活對象的復(fù)制成本就可以完成收集。而老年代中因為對象存活率高涯冠、沒有額外空間對它進行分配擔(dān)保炉奴,就必須使用標(biāo)記-清理或標(biāo)記-整理算法來進行回收。

GC收集器

HotSpot JVM收集器蛇更,7種收集器瞻赶,分為兩塊,上面為新生代收集器派任,下面是老年代收集器砸逊。如果兩個收集器之間存在連線,就說明它們可以搭配使用掌逛。

Serial(串行GC)收集器

Serial收集器是一個新生代收集器师逸,單線程執(zhí)行,使用復(fù)制算法豆混。它在進行垃圾收集時篓像,必須暫停其他所有的工作線程(用戶線程)。是Jvm client模式下默認(rèn)的新生代收集器皿伺。對于限定單個CPU的環(huán)境來說员辩,Serial收集器由于沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率鸵鸥。

ParNew(并行GC)收集器

ParNew收集器其實就是Serial收集器的多線程版本奠滑,除了使用多條線程進行垃圾收集之外,其余行為與Serial收集器一樣妒穴。

Parallel Old(并行GC)收集器

ParallelScavenge收集器也是一個新生代收集器养叛,它也是使用復(fù)制算法的收集器兢榨,又是并行多線程收集器鬓照。Parallel Scavenge收集器的特點是它的關(guān)注點與其他收集器不同霎迫,CMS等收集器的關(guān)注點是盡可能地縮短垃圾收集時用戶線程的停頓時間,而parallel Scavenge收集器的目標(biāo)則是達(dá)到一個可控制的吞吐量汁讼。吞吐量= 程序運行時間/(程序運行時間 + 垃圾收集時間),虛擬機總共運行了100分鐘阔墩。其中垃圾收集花掉1分鐘嘿架,那吞吐量就是99%。

SerialOld(串行GC)收集器

Serial Old是Serial收集器的老年代版本啸箫,它同樣使用一個單線程執(zhí)行收集耸彪,使用“標(biāo)記-整理”算法。主要使用在Client模式下的虛擬機忘苛。

ParallelOld(并行GC)收集器

Parallel Old是ParallelScavenge收集器的老年代版本蝉娜,使用多線程和“標(biāo)記-整理”算法唱较。

CMS(并發(fā)GC)收集器

CMS(ConcurrentMark Sweep)收集器是一種以獲取最短回收停頓時間為目標(biāo)的收集器。CMS收集器是基于“標(biāo)記-清除”算法實現(xiàn)的召川,整個收集過程大致分為4個步驟:

①.初始標(biāo)記(CMSinitial mark)

②.并發(fā)標(biāo)記(CMSconcurrenr mark)

③.重新標(biāo)記(CMSremark)

④.并發(fā)清除(CMSconcurrent sweep)

?? ?其中初始標(biāo)記南缓、重新標(biāo)記這兩個步驟任然需要停頓其他用戶線程。初始標(biāo)記僅僅只是標(biāo)記出GC ROOTS能直接關(guān)聯(lián)到的對象荧呐,速度很快汉形,并發(fā)標(biāo)記階段是進行GC ROOTS 根搜索算法階段,會判定對象是否存活倍阐。而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間概疆,因用戶程序繼續(xù)運行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄,這個階段的停頓時間會比初始標(biāo)記階段稍長峰搪,但比并發(fā)標(biāo)記階段要短岔冀。

?? ?由于整個過程中耗時最長的并發(fā)標(biāo)記和并發(fā)清除過程中,收集器線程都可以與用戶線程一起工作罢艾,所以整體來說楣颠,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的。

CMS收集器的優(yōu)點:并發(fā)收集咐蚯、低停頓童漩,但是CMS還遠(yuǎn)遠(yuǎn)達(dá)不到完美,其主要有三個顯著缺點:

CMS收集器對CPU資源非常敏感春锋。在并發(fā)階段矫膨,雖然不會導(dǎo)致用戶線程停頓,但是會占用CPU資源而導(dǎo)致應(yīng)用程序變慢期奔,總吞吐量下降侧馅。CMS默認(rèn)啟動的回收線程數(shù)是:(CPU數(shù)量+3) / 4。

CMS收集器無法處理浮動垃圾呐萌,可能出現(xiàn)“Concurrent Mode Failure“馁痴,失敗后而導(dǎo)致另一次Full?GC的產(chǎn)生。由于CMS并發(fā)清理階段用戶線程還在運行肺孤,伴隨程序的運行自熱會有新的垃圾不斷產(chǎn)生罗晕,這一部分垃圾出現(xiàn)在標(biāo)記過程之后,CMS無法在本次收集中處理它們赠堵,只好留待下一次GC時將其清理掉小渊。這一部分垃圾稱為“浮動垃圾”。也是由于在垃圾收集階段用戶線程還需要運行茫叭,需要預(yù)留足夠的內(nèi)存空間給用戶線程使用酬屉,因此CMS收集器不能像其他收集器那樣等到老年代幾乎完全被填滿了再進行收集,需要預(yù)留一部分內(nèi)存空間提供并發(fā)收集時的程序運作使用。在默認(rèn)設(shè)置下呐萨,CMS收集器在老年代使用了68%的空間時就會被激活杀饵,也可以通過參數(shù)-XX:CMSInitiatingOccupancyFraction的值來提供觸發(fā)百分比,以降低內(nèi)存回收次數(shù)提高性能垛吗。要是CMS運行期間預(yù)留的內(nèi)存無法滿足程序其他線程需要凹髓,就會出現(xiàn)“ConcurrentMode Failure”失敗,這時候虛擬機將啟動后備預(yù)案:臨時啟用Serial Old收集器來重新進行老年代的垃圾收集怯屉,這樣停頓時間就很長了蔚舀。所以說參數(shù)-XX:CMSInitiatingOccupancyFraction設(shè)置的過高將會很容易導(dǎo)致“Concurrent Mode Failure”失敗,性能反而降低锨络。最后一個缺點赌躺,CMS是基于“標(biāo)記-清除”算法實現(xiàn)的收集器,使用“標(biāo)記-清除”算法收集后羡儿,會產(chǎn)生大量碎片礼患。空間碎片太多時掠归,將會給對象分配帶來很多麻煩缅叠,比如說大對象,內(nèi)存空間找不到連續(xù)的空間來分配不得不提前觸發(fā)一次Full ?GC虏冻。為了解決這個問題肤粱,CMS收集器提供了一個-XX:UseCMSCompactAtFullCollection開關(guān)參數(shù),用于在Full?GC之后增加一個碎片整理過程厨相,還可通過-XX:CMSFullGCBeforeCompaction參數(shù)設(shè)置執(zhí)行多少次不壓縮的Full ?GC之后领曼,跟著來一次碎片整理過程。

G1收集器

G1(GarbageFirst)收集器是JDK1.7提供的一個新收集器蛮穿,G1收集器基于“標(biāo)記-整理”算法實現(xiàn)庶骄,也就是說不會產(chǎn)生內(nèi)存碎片。還有一個特點之前的收集器進行收集的范圍都是整個新生代或老年代践磅,而G1將整個Java堆(包括新生代单刁,老年代)。

垃圾收集器參數(shù)總結(jié)


參數(shù)描述

-XX:+UseSerialGCJvm?運行在Client?模式下的默認(rèn)值府适,打開此開關(guān)后羔飞,使用?Serial + Serial Old?的收集器組合進行內(nèi)存回收

-XX:+UseParNewGC打開此開關(guān)后,使用?ParNew + Serial Old?的收集器進行垃圾回收

-XX:+UseConcMarkSweepGC使用?ParNew + CMS + ?Serial Old?的收集器組合進行內(nèi)存回收细溅,?Serial Old?作為CMS?出現(xiàn)?“Concurrent Mode Failure”?失敗后的后備收集器使用。

-XX:+UseParallelGCJvm?運行在Server?模式下的默認(rèn)值儡嘶,打開此開關(guān)后喇聊,使用?Parallel Scavenge +??Serial Old的收集器組合進行回收

-XX:+UseParallelOldGC使用?Parallel Scavenge +??Parallel?Old?的收集器組合進行回收

-XX:SurvivorRatio新生代中?Eden?區(qū)域與Survivor?區(qū)域的容量比值,默認(rèn)為?8?蹦狂,代表Eden:Subrvivor = 8:1

-XX:PretenureSizeThreshold直接晉升到老年代對象的大小誓篱,設(shè)置這個參數(shù)后朋贬,大于這個參數(shù)的對象將直接在老年代分配

-XX:MaxTenuringThreshold晉升到老年代的對象年齡,每次?Minor GC?之后窜骄,年齡就加?1锦募,當(dāng)超過這個參數(shù)的值時進入老年代

-XX:UseAdaptiveSizePolicy動態(tài)調(diào)整?java?堆中各個區(qū)域的大小以及進入老年代的年齡

-XX:+HandlePromotionFailure是否允許?新生代收集擔(dān)保,進行一次minor gc后, 另一塊Survivor空間不足時邻遏,將直接會在老年代中保留

-XX:?ParallelGCThreads設(shè)置并行?GC?進行內(nèi)存回收的線程數(shù)

-XX:?GCTimeRatioGC?時間占總時間的比列糠亩,默認(rèn)值為?99?,即允許1%?的?GC時間准验,僅在使用Parallel Scavenge?收集器時有效

-XX:?MaxGCPauseMillis設(shè)置?GC?的最大停頓時間赎线,在?Parallel Scavenge?收集器下有效

-XX:CMSInitiatingOccupancyFraction設(shè)置?CMS?收集器在老年代空間被使用多少后出發(fā)垃圾收集,默認(rèn)值為?68%?糊饱,僅在CMS?收集器時有效垂寥,?-XX:CMSInitiatingOccupancyFraction=70

-XX:+UseCMSCompactAtFullCollection由于?CMS?收集器會產(chǎn)生碎片,此參數(shù)設(shè)置在垃圾收集器后是否需要一次內(nèi)存碎片整理過程另锋,僅在?CMS?收集器時有效

-XX:+CMSFullGCBeforeCompaction設(shè)置?CMS?收集器在進行若干次垃圾收集后再進行一次內(nèi)存碎片整理過程滞项,通常與?UseCMSCompactAtFullCollection?參數(shù)一起使用

-XX:+UseFastAccessorMethods原始類型優(yōu)化

-XX:+DisableExplicitGC是否關(guān)閉手動?System.gc

-XX:+CMSParallelRemarkEnabled降低標(biāo)記停頓

-XX:LargePageSizeInBytes內(nèi)存頁的大小不可設(shè)置過大,會影響?Perm?的大小夭坪,-XX:LargePageSizeInBytes=128m

?

Client文判、Server模式默認(rèn)GC新生代GC方式老年代和持久代GC方式

ClientSerial 串行GCSerial Old?串行GC

ServerParallel Scavenge ?并行回收GCParallel Old 并行GC


?Sun/oracle JDK GC組合方式新生代GC方式老年代和持久代GC方式

-XX:+UseSerialGCSerial 串行GCSerial Old?串行GC

-XX:+UseParallelGCParallel Scavenge ?并行回收GCSerial Old??并行GC

-XX:+UseConcMarkSweepGCParNew?并行GCCMS 并發(fā)GC

當(dāng)出現(xiàn)“Concurrent Mode Failure”時

采用Serial Old?串行GC

-XX:+UseParNewGCParNew?并行GCSerial Old?串行GC

-XX:+UseParallelOldGCParallel Scavenge ?并行回收GCParallel Old 并行GC

-XX:+UseConcMarkSweepGC

-XX:+UseParNewGC

Serial 串行GCCMS 并發(fā)GC

當(dāng)出現(xiàn)“Concurrent Mode Failure”時

采用Serial Old?串行GC

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市台舱,隨后出現(xiàn)的幾起案子律杠,更是在濱河造成了極大的恐慌,老刑警劉巖竞惋,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柜去,死亡現(xiàn)場離奇詭異,居然都是意外死亡拆宛,警方通過查閱死者的電腦和手機嗓奢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浑厚,“玉大人股耽,你說我怎么就攤上這事∏” “怎么了物蝙?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長敢艰。 經(jīng)常有香客問我诬乞,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任震嫉,我火速辦了婚禮森瘪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘票堵。我一直安慰自己扼睬,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布悴势。 她就那樣靜靜地躺著窗宇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瞳浦。 梳的紋絲不亂的頭發(fā)上担映,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機與錄音叫潦,去河邊找鬼蝇完。 笑死,一個胖子當(dāng)著我的面吹牛矗蕊,可吹牛的內(nèi)容都是我干的短蜕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼傻咖,長吁一口氣:“原來是場噩夢啊……” “哼朋魔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卿操,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤警检,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后害淤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扇雕,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年窥摄,在試婚紗的時候發(fā)現(xiàn)自己被綠了镶奉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡崭放,死狀恐怖哨苛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情币砂,我是刑警寧澤建峭,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站决摧,受9級特大地震影響亿蒸,放射性物質(zhì)發(fā)生泄漏使碾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一祝懂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拘鞋,春花似錦砚蓬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隔躲,卻和暖如春摩梧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宣旱。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工仅父, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浑吟。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓笙纤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親组力。 傳聞我的和親對象是個殘疾皇子省容,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方燎字,同時不同JDK版本的...
    高廣超閱讀 15,607評論 3 83
  • 原文閱讀 前言 這段時間懈怠了腥椒,罪過! 最近看到有同事也開始用上了微信公眾號寫博客了候衍,挺好的~給他們點贊笼蛛,這博客我...
    碼農(nóng)戲碼閱讀 5,972評論 2 31
  • 1.一些概念 1.1.數(shù)據(jù)類型 Java虛擬機中,數(shù)據(jù)類型可以分為兩類:基本類型和引用類型脱柱》サ基本類型的變量保存原始...
    落落落落大大方方閱讀 4,541評論 4 86
  • JVM內(nèi)存模型Java虛擬機(Java Virtual Machine=JVM)的內(nèi)存空間分為五個部分,分別是: ...
    光劍書架上的書閱讀 2,514評論 2 26
  • 此生愿遇牛鬼蛇神榨为,歌行且論殘缺惨好。 今天看著一些人,真的覺得陌生了随闺,有一些自己一直沒深想日川,直到今天,才恍然發(fā)覺有些事...
    章魚獵人閱讀 209評論 0 1