JVM學(xué)習(xí)(三)JVM內(nèi)存模型

引言

本文希望以另外一種維度的思考方式來學(xué)習(xí)JVM內(nèi)存模型,希望自己能從設(shè)計(jì)原理的維度考慮為什么存在颇蜡?有什么價值产上?解決什么問題撑蒜?

在學(xué)習(xí)JVM內(nèi)存模型之前歹啼,先回顧下前面兩章的內(nèi)容點(diǎn)類加載器機(jī)制與類加載器。與本章內(nèi)容存在關(guān)聯(lián)關(guān)系座菠。


JVM內(nèi)存模型與上下游

JVM內(nèi)存模型

類加載器將Class文件讀取后狸眼,放到運(yùn)行時數(shù)據(jù)區(qū),然后執(zhí)行引擎執(zhí)行或調(diào)用本地接口浴滴、本地庫拓萌。

一、JVM內(nèi)存模型分類

JVM內(nèi)存模型從線程維度歸類分為:線程私有內(nèi)存升略、線程共享內(nèi)存微王、以及不在堆內(nèi)的直接內(nèi)存屡限。
如下圖:

JVM內(nèi)存模型線程維度分類

(一)直接內(nèi)存

為什么先講直接內(nèi)存? 因?yàn)橹苯觾?nèi)存更準(zhǔn)確的說不在JVM的堆范圍內(nèi)炕倘,但JVM會使用到钧大。故此先介紹直接內(nèi)存。

直接內(nèi)存并不是JVM運(yùn)行時數(shù)據(jù)區(qū)的一部分罩旋,但也會唄頻繁的使用啊央。在JDK 1.4引入的NIO提供了機(jī)遇Channel與Buffer的IO方式,它可以使用Native函數(shù)庫直接分配堆外的內(nèi)存涨醋,然后使用DirectByteBuffer對象作為這塊內(nèi)存的引用進(jìn)行操作瓜饥,這樣舊避免了Java堆和Native堆來回賦值數(shù)據(jù),因此在一些場景中可以顯著提高性能浴骂。
本機(jī)直接內(nèi)存的分配不會收到Java堆大小的限制乓土,(即不會遵守-Xms、-Xmx等配置)靠闭。但仍然是內(nèi)存帐我,則肯定還是會收到本機(jī)總內(nèi)存大小+尋址空間的限制坎炼,因此擴(kuò)展時也會出現(xiàn)OutOfMemoryError異常愧膀。

(二)線程私有型內(nèi)存

線程私有型內(nèi)存 由三種:程序寄存器、Java棧谣光、本地方法棧檩淋。
后面會詳細(xì)講解..

(三)線程共享型內(nèi)存

線程共享型內(nèi)存 又分為兩種:Java堆和本地方法區(qū)。
后面會詳細(xì)講解..

二萄金、程序計(jì)數(shù)器 - Program Counter Register

程序計(jì)數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間蟀悦,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。在虛擬機(jī)的概念模型里(僅是概念模型氧敢,各種虛擬機(jī)可能會通過一些更高效的方式去實(shí)現(xiàn))日戈,字節(jié)碼解釋器工作時就是通過改變這個計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支孙乖、循環(huán)浙炼、跳轉(zhuǎn)、異常處理唯袄、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計(jì)數(shù)器來完成弯屈。

由于Java虛擬機(jī)的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實(shí)現(xiàn)的,在任何一個確定的時刻恋拷,一個處理器(對于多核處理器來說是一個內(nèi)核)只會執(zhí)行一條線程中的指令资厉。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置蔬顾,每條線程都需要有一個獨(dú)立的程序計(jì)數(shù)器宴偿,各條線程之間的計(jì)數(shù)器互不影響湘捎,獨(dú)立存儲,我們稱這類內(nèi)存區(qū)域?yàn)?code>“線程私有”的內(nèi)存窄刘。

如果線程正在執(zhí)行的是一個Java方法消痛,這個計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址;如果正在執(zhí)行的是Natvie方法都哭,這個計(jì)數(shù)器值則為空(Undefined)秩伞。

此內(nèi)存區(qū)域是唯一一個在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。

白話文: 程序計(jì)數(shù)器 可以從計(jì)算機(jī)原型中理解欺矫,它類似與CPU寄存器纱新;用于記錄JVM的各自獨(dú)立線程的執(zhí)行指令。當(dāng)然是線程私有穆趴。

三脸爱、Java棧 - Java Stack

Java棧 - Java Stack 與程序計(jì)數(shù)器一樣,Java虛擬機(jī)棧(Java Virtual Machine Stacks)也是線程私有的未妹,它的生命周期與線程相同簿废。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會同時創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表、操作棧络它、動態(tài)鏈接族檬、方法出口等信息。每一個方法被調(diào)用直至執(zhí)行完成的過程化戳,就對應(yīng)著一個棧幀在虛擬機(jī)棧中從入棧到出棧的過程单料。

局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean、byte点楼、char扫尖、short、int掠廓、float换怖、long、double)蟀瞧、對象引用(reference類型沉颂,它不等同于對象本身,根據(jù)不同的虛擬機(jī)實(shí)現(xiàn)黄橘,它可能是一個指向?qū)ο笃鹗嫉刂返囊弥羔樥桌溃部赡苤赶蛞粋€代表對象的句柄或者其他與此對象相關(guān)的位置)和returnAddress類型(指向了一條字節(jié)碼指令的地址)。

其中64位長度的long和double類型的數(shù)據(jù)會占用2個局部變量空間(Slot)塞关,其余的數(shù)據(jù)類型只占用1個抬探。局部變量表所需的內(nèi)存空間在編譯期間完成分配,當(dāng)進(jìn)入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的小压,在方法運(yùn)行期間不會改變局部變量表的大小线梗。

在Java虛擬機(jī)規(guī)范中,對這個區(qū)域規(guī)定了兩種異常狀況:

  • 如果線程請求的棧深度大于虛擬機(jī)所允許的深度怠益,將拋出StackOverflowError異常仪搔;
  • 如果虛擬機(jī)棧可以動態(tài)擴(kuò)展(當(dāng)前大部分的Java虛擬機(jī)都可動態(tài)擴(kuò)展蜻牢,只不過Java虛擬機(jī)規(guī)范中也允許固定長度的虛擬機(jī)棧)烤咧,當(dāng)擴(kuò)展時無法申請到足夠的內(nèi)存時會拋出OutOfMemoryError異常。

如下圖:


Java棧

(一)局部變量表

局部變量表是一組變量值存儲空間抢呆,用于存放方法參數(shù)方法內(nèi)部定義的局部變量煮嫌。在Java程序被編譯成Class文件時,就在方法的Code屬性的max_locals數(shù)據(jù)項(xiàng)中確定了該方法所需要分配的最大局部變量表的容量抱虐。

局部變量表的容量以變量槽(Slot)為最小單位昌阿,32位虛擬機(jī)中一個Slot可以存放一個32位以內(nèi)的數(shù)據(jù)類型(boolean、byte恳邀、char懦冰、short、int谣沸、float刷钢、reference和returnAddress八種)。

reference類型虛擬機(jī)規(guī)范沒有明確說明它的長度鳄抒,但一般來說闯捎,虛擬機(jī)實(shí)現(xiàn)至少都應(yīng)當(dāng)能從此引用中直接或者間接地查找到對象在Java堆中的起始地址索引和方法區(qū)中的對象類型數(shù)據(jù)椰弊。

returnAddress類型是為字節(jié)碼指令jsr许溅、jsr_w和ret服務(wù)的,它指向了一條字節(jié)碼指令的地址秉版。

虛擬機(jī)是使用局部變量表完成參數(shù)值到參數(shù)變量列表的傳遞過程的贤重,如果是實(shí)例方法(非static),那么局部變量表的第0位索引的Slot默認(rèn)是用于傳遞方法所屬對象實(shí)例的引用清焕,在方法中通過this訪問并蝗。

Slot是可以重用的,當(dāng)Slot中的變量超出了作用域秸妥,那么下一次分配Slot的時候滚停,將會覆蓋原來的數(shù)據(jù)。Slot對對象的引用會影響GC(要是被引用粥惧,將不會被回收)键畴。
系統(tǒng)不會為局部變量賦予初始值(實(shí)例變量和類變量都會被賦予初始值)。也就是說不存在類變量那樣的準(zhǔn)備階段。

(二)操作數(shù)棧

操作數(shù)棧 和局部變量區(qū)一樣起惕,操作數(shù)棧也是被組織成一個以字長為單位的數(shù)組涡贱。但是和前者不同的是,它不是通過索引來訪問惹想,而是通過標(biāo)準(zhǔn)的棧操作——壓棧和出椢蚀剩—來訪問的。比如嘀粱,如果某個指令把一個值壓入到操作數(shù)棧中激挪,稍后另一個指令就可以彈出這個值來使用。

虛擬機(jī)在操作數(shù)棧中存儲數(shù)據(jù)的方式和在局部變量區(qū)中是一樣的:如int锋叨、long灌灾、float、double悲柱、reference和returnType的存儲锋喜。對于byte、short以及char類型的值在壓入到操作數(shù)棧之前豌鸡,也會被轉(zhuǎn)換為int嘿般。

虛擬機(jī)把操作數(shù)棧作為它的工作區(qū)——大多數(shù)指令都要從這里彈出數(shù)據(jù),執(zhí)行運(yùn)算涯冠,然后把結(jié)果壓回操作數(shù)棧炉奴。比如,iadd指令就要從操作數(shù)棧中彈出兩個整數(shù)蛇更,執(zhí)行加法運(yùn)算瞻赶,其結(jié)果又壓回到操作數(shù)棧中,看看下面的示例派任,它演示了虛擬機(jī)是如何把兩個int類型的局部變量相加砸逊,再把結(jié)果保存到第三個局部變量的:

begin
iload_0    // push the int in local variable 0 ontothe stack
iload_1    //push the int in local variable 1 onto the stack
iadd       // pop two ints, add them, push result
istore_2   // pop int, store into local variable 2
end

在這個字節(jié)碼序列里,前兩個指令iload_0和iload_1將存儲在局部變量中索引為0和1的整數(shù)壓入操作數(shù)棧中掌逛,其后iadd指令從操作數(shù)棧中彈出那兩個整數(shù)相加师逸,再將結(jié)果壓入操作數(shù)棧。第四條指令istore_2則從操作數(shù)棧中彈出結(jié)果豆混,并把它存儲到局部變量區(qū)索引為2的位置篓像。下圖詳細(xì)表述了這個過程中局部變量和操作數(shù)棧的狀態(tài)變化,圖中沒有使用的局部變量區(qū)和操作數(shù)棧區(qū)域以空白表示皿伺。
如下圖:


操作數(shù)棧操作流程

(三)動態(tài)鏈接

動態(tài)連接 : 虛擬機(jī)運(yùn)行的時候,運(yùn)行時常量池會保存大量的符號引用员辩,這些符號引用可以看成是每個方法的間接引用。如果代表?xiàng)珹的方法想調(diào)用代表?xiàng)珺的方法鸵鸥,那么這個虛擬機(jī)的方法調(diào)用指令就會以B方法的符號引用作為參數(shù)奠滑,但是因?yàn)榉栆貌⒉皇侵苯又赶虼鞡方法的內(nèi)存位置,所以在調(diào)用之前還必須要將符號引用轉(zhuǎn)換為直接引用,然后通過直接引用才可以訪問到真正的方法养叛。

  • 如果符號引用是在類加載階段或者第一次使用的時候轉(zhuǎn)化為直接應(yīng)用种呐,那么這種轉(zhuǎn)換成為靜態(tài)解析
  • 如果是在運(yùn)行期間轉(zhuǎn)換為直接引用弃甥,那么這種轉(zhuǎn)換就成為動態(tài)連接爽室。

(四) 返回地址

方法的返回分為兩種情況:

  • 一種是正常退出,退出后會根據(jù)方法的定義來決定是否要傳返回值給上層的調(diào)用者淆攻。
  • 一種是異常導(dǎo)致的方法結(jié)束阔墩,這種情況是不會傳返回值給上層的調(diào)用方法。

不過無論是那種方式的方法結(jié)束瓶珊,在退出當(dāng)前方法時都會跳轉(zhuǎn)到當(dāng)前方法被調(diào)用的位置啸箫。

  • 如果方法是正常退出的,則調(diào)用者的PC計(jì)數(shù)器的值就可以作為返回地址伞芹;
  • 如果是因?yàn)楫惓M顺龅耐粒瑒t是需要通過異常處理表來確定

方法的的一次調(diào)用就對應(yīng)著棧幀在虛擬機(jī)棧中的一次入棧出棧操作唱较,因此方法退出時可能做的事情包括:恢復(fù)上層方法的局部變量表以及操作數(shù)棧扎唾,如果有返回值的話,就把返回值壓入到調(diào)用者棧幀的操作數(shù)棧中南缓,還會把PC計(jì)數(shù)器的值調(diào)整為方法調(diào)用入口的下一條指令胸遇。

關(guān)于Java棧的更多解析,請查閱下文汉形,我覺得寫的很好纸镊。
http://www.reibang.com/p/15932712fcb4
這張圖很有故事...

局部變量表和操作數(shù)棧關(guān)系

四、本地方法棧 - Native Method Stack

本地方法棧(Native MethodStacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的概疆,其區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java 方法(也就是字節(jié)碼)服務(wù)逗威,而本地方法棧則是為虛擬機(jī)使用到的Native 方法服務(wù)。本地方法棧也是```線程私有``的届案。虛擬機(jī)規(guī)范中對本地方法棧中的方法使用的語言庵楷、使用方式與數(shù)據(jù)結(jié)構(gòu)并沒有強(qiáng)制規(guī)定,因此具體的虛擬機(jī)可以自由實(shí)現(xiàn)它楣颠。甚至有的虛擬機(jī)(譬如Sun HotSpot 虛擬機(jī))直接就把本地方法棧和虛擬機(jī)棧合二為一。

與虛擬機(jī)棧一樣咐蚯,本地方法棧區(qū)域也會拋出StackOverflowErrorOutOfMemoryError異常童漩。

五、方法區(qū) - Method Area

方法區(qū)在一個JVM 實(shí)例的內(nèi)部春锋,類型信息被存儲在一個稱為方法區(qū)的內(nèi)存邏輯區(qū)中矫膨。類型信息是由類加載器在類加載時從類文件中提取出來的。類(靜態(tài))變量也存儲在方法區(qū)中。

簡單說方法區(qū)用來存儲類型的元數(shù)據(jù)信息侧馅,一個.class文件是類被java虛擬機(jī)使用之前的表現(xiàn)形式危尿,一旦這個類要被使用,java虛擬機(jī)就會對其進(jìn)行裝載馁痴、連接(驗(yàn)證谊娇、準(zhǔn)備、解析)和初始化罗晕,而裝載后的結(jié)果就是由.class文件轉(zhuǎn)變?yōu)榉椒▍^(qū)中的一段特定的數(shù)據(jù)結(jié)構(gòu)济欢。

① 方法區(qū)數(shù)據(jù)結(jié)構(gòu)

這個數(shù)據(jù)結(jié)構(gòu)會存儲如下信息:

  • 類型信息:全限定名、直接超類的全限定名小渊、類的類型還是接口類型法褥、訪問修飾符、直接超接口的全限定名的有序列表
  • 字段信息:字段名酬屉、字段類型半等、字段的修飾符
  • 方法信息:方法名、方法返回類型呐萨、方法參數(shù)的數(shù)量和類型(按照順序)酱鸭、方法的修飾符
  • 其他信息:除了常量以外的所有類(靜態(tài))變量、一個指向ClassLoader的指針垛吗、一個指向Class對象的指針凹髓、常量池(常量數(shù)據(jù)以及對其他類型的符號引用)

關(guān)于JVM中 常量池的解釋,這篇文章解析的比較好怯屉。
https://my.oschina.net/u/867830/blog/1609952
https://www.cnblogs.com/iyangyuan/p/4631696.html

常量池

② 方法區(qū)的特點(diǎn)

方法區(qū)主要有以下幾個特點(diǎn):

  • 1.方法區(qū)是線程安全的蔚舀,由于所有的線程都共享方法區(qū),所以方法區(qū)里的數(shù)據(jù)訪問必須被設(shè)計(jì)成線程安全的锨络。
  • 2赌躺、方法區(qū)的大小不必是固定的,JVM可根據(jù)應(yīng)用需要動態(tài)調(diào)整羡儿。
  • 3礼患、方法區(qū)也可被垃圾收集,當(dāng)某個類不在被使用(不可觸及)時掠归,JVM將卸載這個類缅叠,進(jìn)行垃圾收集。

HotSpot 虛擬機(jī)虏冻,很多人愿意把方法區(qū)稱為“永久代”(Permanent Generation)肤粱。本質(zhì)上兩者并不等價,僅僅是因?yàn)镠otSpot 虛擬機(jī)的設(shè)計(jì)團(tuán)隊(duì)選擇把GC 分代收集擴(kuò)展至方法區(qū)厨相,或者說使用永久代來實(shí)現(xiàn)方法區(qū)而已领曼。對于其他虛擬機(jī)來說是不存在永久代的概念的鸥鹉。
當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時,將拋出OutOfMemoryError異常庶骄。

③ 方法區(qū)內(nèi)存大小設(shè)置:

jdk6毁渗,jdk7 永久區(qū)
-XX:PermSize=10M 初始化方法區(qū)大小為10M。
-XX:MaxPermSize 方法區(qū)最大內(nèi)存為10M单刁。
-XX:PrintGCDetails 打印日志詳情灸异。
jdk8 元數(shù)據(jù)區(qū)
-XX:MetaspaceSize=10M
-XX:MaxMetaspaceSize=10M

需要注意一點(diǎn):
jdk8中永久區(qū)被移除了,取而代之的是元數(shù)據(jù)區(qū)幻碱,可能方法區(qū)依賴jvm的內(nèi)存吧绎狭。
不同的是元數(shù)據(jù)區(qū)是堆外直接內(nèi)存,與方法永久區(qū)不同褥傍,在不指定大小的情況下儡嘶,虛擬機(jī)會耗盡所有可用的系統(tǒng)內(nèi)存。
元數(shù)據(jù)區(qū)發(fā)生溢出恍风,虛擬機(jī)一樣拋出異常蹦狂,如下:java.lang.OutOfMemoryError Metaspace

六、Java 堆 - Heap 部分

終于說到今天的大主角了 Java堆 Heap朋贬。

(一)Java堆

對于大多數(shù)應(yīng)用來說凯楔,Java堆(Java Heap)是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域锦募,在虛擬機(jī)啟動時創(chuàng)建摆屯。此內(nèi)存區(qū)域的唯一目的就是存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存糠亩。

Java堆是垃圾收集器管理的主要區(qū)域虐骑,因此很多時候也被稱做“GC堆”。如果從內(nèi)存回收的角度看赎线,由于現(xiàn)在收集器基本都是采用的分代收集算法廷没,所以Java堆中還可以細(xì)分為:新生代和老年代;再細(xì)致一點(diǎn)的有Eden空間垂寥、From Survivor空間颠黎、To Survivor空間等。

根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定滞项,Java堆可以處于物理上不連續(xù)的內(nèi)存空間中狭归,只要邏輯上是連續(xù)的即可,就像我們的磁盤空間一樣蓖扑。在實(shí)現(xiàn)時唉铜,既可以實(shí)現(xiàn)成固定大小的,也可以是可擴(kuò)展的律杠,不過當(dāng)前主流的虛擬機(jī)都是按照可擴(kuò)展來實(shí)現(xiàn)的(通過-Xmx和-Xms控制)潭流。

如果在堆中沒有內(nèi)存完成實(shí)例分配,并且堆也無法再擴(kuò)展時柜去,將會拋出OutOfMemoryError異常灰嫉。

堆大小 = 新生代 + 老年代。其中嗓奢,堆的大小可以通過參數(shù) –Xms讼撒、-Xmx 來指定。

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

(二) 新生代

程序新創(chuàng)建的對象都是從新生代分配內(nèi)存炎滞,新生代由Eden Space和兩塊相同大小的Survivor Space(通常又稱S0和S1或From和To)構(gòu)成。
可通過-Xmn參數(shù)來指定新生代的大形芷颉册赛;也可以通過-XX:SurvivorRation來調(diào)整Eden Space及SurvivorSpace的大小。

  • 1震嫉、新生代的初始值NewSize默認(rèn)為1M森瘪,最大值需要設(shè)置,可以通過參數(shù)-XX:NewSize-XX:MaxNewSize-Xmn進(jìn)行設(shè)置票堵;
  • 2扼睬、為老年代與新生代的大小比值,默認(rèn)為2:1悴势;
  • 3窗宇、SurvivorRatio為新生代中Eden和Survivor的大小比值,默認(rèn)為8:1
    Edem : from : to = 8 :1 : 1
    可以通過參數(shù)-XX:SurvivorRatio 來設(shè)定 )瞳浦,即: Eden = 8/10 的新生代空間大小担映,from = to = 1/10 的新生代空間大小。

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

新生代實(shí)際可用的內(nèi)存空間為 9/10 ( 即90% )的新生代空間矗蕊。

Edan區(qū) 短蜕、From區(qū) - Surivivor 0 、To 區(qū) - Surivivor 1

    1. 在未開始GC的時候傻咖,對象只會存在于Eden區(qū)和名為“From”的Survivor區(qū)朋魔,Survivor區(qū)“To”是空的。
    1. 緊接著進(jìn)行GC卿操,Eden區(qū)中所有存活的對象都會被復(fù)制到“To”警检,而在“From”區(qū)中孙援,仍存活的對象會根據(jù)他們的年齡值來決定去向。
    1. 年齡達(dá)到一定值(年齡閾值扇雕,可以通過-XX:MaxTenuringThreshold來設(shè)置)的對象會被移動到年老代中疤估,沒有達(dá)到閾值的對象會被復(fù)制到“To”區(qū)域地熄。經(jīng)過這次GC后另假,Eden區(qū)和From區(qū)已經(jīng)被清空莹捡。
    1. 這個時候,“From”和“To”會交換他們的角色哨苛,也就是新的“To”就是上次GC前的“From”鸽凶,新的“From”就是上次GC前的“To”。不管怎樣建峭,都會保證名為To的Survivor區(qū)域是空的玻侥。
    1. Minor GC會一直重復(fù)這樣的過程,直到“To”區(qū)被填滿迹缀,“To”區(qū)被填滿之后使碾,會將所有對象移動到年老代中。
Minor GC祝懂、FullGC

堆是GC收集垃圾的主要區(qū)域票摇。GC 分為兩種:Minor GC、FullGC ( 或稱為 Major GC )砚蓬。

  • Minor GC 是發(fā)生在新生代中的垃圾收集動作矢门,所采用的是復(fù)制算法。

    • 當(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 歲)省容,這些對象就會成為老年代抖拴。
    • 但這也不是一定的,對于一些較大的對象 ( 即需要分配一塊較大的連續(xù)內(nèi)存空間 ) 則是直接進(jìn)入到老年代腥椒。
  • Full GC 是發(fā)生在老年代的垃圾收集動作阿宅,所采用的是標(biāo)記-清除算法候衍。
    Full GC 發(fā)生的次數(shù)不會有 Minor GC 那么頻繁,并且做一次 Full GC 要比進(jìn)行一次 Minor GC 的時間更長家夺。
    標(biāo)記-清除算法收集垃圾的時候會產(chǎn)生許多的內(nèi)存碎片 ( 即不連續(xù)的內(nèi)存空間 )脱柱,此后需要為較大的對象分配內(nèi)存空間時伐弹,若無法找到足夠的連續(xù)的內(nèi)存空間拉馋,就會提前觸發(fā)一次 GC 的收集動作。

(三) 老生代

用于存放經(jīng)過多次新生代GC仍然存活的對象惨好,例如緩存對象煌茴,新建的對象也有可能直接進(jìn)入老年代,主要有兩種情況:

  • 1日川、大對象蔓腐,可通過啟動參數(shù)設(shè)置-XX:PretenureSizeThreshold=1024(單位為字節(jié),默認(rèn)為0)來代表超過多大時就不在新生代分配龄句,而是直接在老年代分配回论。
  • 2、大的數(shù)組對象分歇,且數(shù)組中無引用外部對象傀蓉。

老年代所占的內(nèi)存大小為-Xmx對應(yīng)的值減去-Xmn對應(yīng)的值。
如果在堆中沒有內(nèi)存完成實(shí)例分配职抡,并且堆也無法再擴(kuò)展時葬燎,將會拋出OutOfMemoryError異常。

七缚甩、JVM各空間分配

各空間分配參數(shù)
  • Java堆 :
    • -Xms 初始堆大小
    • -Xmx 最大堆大小
    • -XX:NewSize 初始新生代大小
    • -XX:MaxNewSize 最大新生代大小
  • 方法區(qū) Method Area
    • -XX:PermSize 初始方法區(qū)大小
    • -XX:MaxPermSize 最大方法區(qū)大小
  • Java棧 : -Xss 每個線程棧的大小

最后谱净,小結(jié)

小結(jié)

參考

http://www.ityouknow.com/jvm/2017/08/29/GC-garbage-collection.html
https://blog.csdn.net/u012799221/article/details/73180509
http://www.reibang.com/p/fd1d4f21733a
https://blog.csdn.net/zjf280441589/article/details/53437703
深入理解Java虛擬機(jī)

https://www.cnblogs.com/E-star/p/5556188.html
https://www.cnblogs.com/SaraMoring/p/5713732.html
https://blog.csdn.net/SunshineLPL/article/details/78318709?locationNum=9&fps=1
https://blog.csdn.net/u012152619/article/details/46968883
https://www.cnblogs.com/bude/p/6304512.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市擅威,隨后出現(xiàn)的幾起案子壕探,更是在濱河造成了極大的恐慌,老刑警劉巖郊丛,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件李请,死亡現(xiàn)場離奇詭異,居然都是意外死亡宾袜,警方通過查閱死者的電腦和手機(jī)捻艳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庆猫,“玉大人认轨,你說我怎么就攤上這事≡屡啵” “怎么了嘁字?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵恩急,是天一觀的道長。 經(jīng)常有香客問我纪蜒,道長衷恭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任纯续,我火速辦了婚禮随珠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猬错。我一直安慰自己窗看,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布倦炒。 她就那樣靜靜地躺著显沈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逢唤。 梳的紋絲不亂的頭發(fā)上拉讯,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機(jī)與錄音鳖藕,去河邊找鬼魔慷。 笑死,一個胖子當(dāng)著我的面吹牛吊奢,可吹牛的內(nèi)容都是我干的盖彭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼页滚,長吁一口氣:“原來是場噩夢啊……” “哼召边!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起裹驰,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤隧熙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后幻林,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贞盯,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年沪饺,在試婚紗的時候發(fā)現(xiàn)自己被綠了躏敢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡整葡,死狀恐怖件余,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤啼器,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布旬渠,位于F島的核電站,受9級特大地震影響端壳,放射性物質(zhì)發(fā)生泄漏告丢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一损谦、第九天 我趴在偏房一處隱蔽的房頂上張望岖免。 院中可真熱鬧,春花似錦成翩、人聲如沸觅捆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至掂摔,卻和暖如春术羔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乙漓。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工级历, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叭披。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓寥殖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涩蜘。 傳聞我的和親對象是個殘疾皇子嚼贡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

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