《深入理解Java虛擬機》是我個人讀過的第一本關于JVM方面的書籍利职。十分有幸能夠讀到這本書趣效,在此對作者表示深刻的敬意
不知道有沒有人和我一樣有類似的情況,就是一本書讀完眼耀,經(jīng)過一段時間之后英支,林林總總最后留在腦子里的并不多,很多東西又還給了作者哮伟。有人可能會說干花,之所以會遺忘,是因為你根本沒有理解楞黄。我并不否認這點池凄,說實話,很多書讀過一遍之后都會存在沒有讀懂的部分鬼廓。但是隨著我們閱歷的豐富以及期間不斷的學習肿仑,過去不懂的部分終究會慢慢讀懂。鑒于這種情況,我覺得讀書筆記還是很有必要:讀書期間總結(jié)歸納尤慰,日后溫故知新
筆記僅僅是我個人對此書的一份總結(jié)馏锡,提綱挈領。如需了解細節(jié)伟端,請完整閱讀原著杯道,這本書我個人也強烈推薦。下面责蝠,開始《深入理解Java虛擬機》讀書筆記的第一篇--Java內(nèi)存區(qū)域
運行時數(shù)據(jù)區(qū)域
JVM在運行Java程序時將內(nèi)存區(qū)域劃分為不同的部分党巾,這些區(qū)域有各自的用途以及各自的內(nèi)存管理策略
在Java虛擬機的概念模型中,這些區(qū)域大致可以分為:程序計數(shù)器(Program Counter Register)霜医、虛擬機棧(VM Stack)齿拂、本地方法棧(Native Method Stack)、堆(Heap)肴敛、方法區(qū)(Method Area)
其中前三者是線程隔離的內(nèi)存區(qū)域署海,后兩者是線程共享的內(nèi)存區(qū)域
1.程序計數(shù)器
程序計數(shù)器可以簡單理解為線程執(zhí)行字節(jié)碼的行號指示器。由于在線程切換后需要恢復到程序的執(zhí)行位置医男,因此每個線程都有各自的程序計數(shù)器
2.虛擬機棧
虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型叹侄,方法在執(zhí)行的時候會創(chuàng)建棧幀。棧幀用于存儲方法執(zhí)行時所需的局部變量表昨登、操作數(shù)棧、動態(tài)鏈接贯底、方法出口等信息丰辣。方法的執(zhí)行伴隨著棧幀在虛擬機棧中的入棧及出棧
局部變量表存儲了基本數(shù)據(jù)類型、對象引用禽捆、返回地址
Java虛擬機規(guī)范對此區(qū)域規(guī)定了兩種異常情況:當線程請求的棧深度大于虛擬機允許的最大深度將觸發(fā)StackOverflowError笙什;如果虛擬機棧在動態(tài)擴展時無法申請到足夠的內(nèi)存將觸發(fā)OutOfMemoryError
3.本地方法棧
本地方法棧與虛擬機棧作用類似,區(qū)別在于虛擬機棧用于Java方法執(zhí)行胚想,而本地方法棧用于本地方法執(zhí)行
有些虛擬機甚至不區(qū)分本地方法棧和虛擬機棧琐凭,而是將它們合二為一
同樣本地方法棧也會觸發(fā)StackOverflowError和OutOfMemoryError
4.堆
堆用于存放對象實例,可以細分為新生代和老年代浊服,進一步可以細分為Eden空間统屈、From Survivor空間、To Survivor空間等牙躺。進一步細分區(qū)域的目的是根據(jù)對象的特征更好的分配以及回收內(nèi)存空間
堆在物理上可以是不連續(xù)的空間愁憔,只要在邏輯上是連續(xù)的即可。如果當前堆內(nèi)存已經(jīng)用完并且無法動態(tài)擴展的時候會觸發(fā)OutOfMemoryError
5.方法區(qū)
方法區(qū)主要用于存放已經(jīng)被虛擬機加載的類信息孽拷、常量吨掌、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)
運行時常量池是方法區(qū)的一部分,主要用于存放編譯期生成的字面量和符號引用膜宋,另外在運行時也可以將新的常量加入池中
這個區(qū)域的內(nèi)存回收通常收益較低窿侈,主要是針對常量池的回收以及對類型的卸載(對類型卸載的要求十分嚴苛)
同樣,當方法區(qū)無法滿足內(nèi)存分配需求時秋茫,將會觸發(fā)OutOfMemoryError
6.直接內(nèi)存
直接內(nèi)存并非Java虛擬機規(guī)范中定義的內(nèi)存區(qū)域史简,但是在大量使用NIO的程序中有可能觸發(fā)OutOfMemoryError異常
NIO基于Channel和Buffer,可以直接使用本地方法分配堆外內(nèi)存学辱,然后通過存儲在堆中的DirectByteBuffer對象作為這塊堆外內(nèi)存的引用進行操作乘瓤。雖然堆外內(nèi)存不會受到Java堆大小的限制,但是仍然會受制于物理內(nèi)存以及操作系統(tǒng)的限制策泣。當各內(nèi)存區(qū)域總和大于物理內(nèi)存或者達到操作系統(tǒng)限制衙傀,從而導致動態(tài)擴展時觸發(fā)OutOfMemoryError
對象探秘
不同的虛擬機,對于對象的創(chuàng)建萨咕、布局和訪問會有所差異统抬,下面僅以HotSpot的堆內(nèi)存為例進行介紹
1.對象的創(chuàng)建
#類檢查及類加載
虛擬機在遇到new指令的時候,首先會去常量池檢查類的符號引用危队,如果發(fā)現(xiàn)沒有對此類進行加載聪建、解析厕怜、初始化绑莺,那么首先會對該類進行加載
#內(nèi)存分配
之后虛擬機會為該對象分配內(nèi)存。由于對象所需內(nèi)存在類加載后就可以確定览妖,因此分配內(nèi)存實際上就是從未使用的堆內(nèi)存中劃分出一塊確定大小的存儲空間簿盅。此過程有兩種方式:
1)對于規(guī)整的堆內(nèi)存挥下,直接將指針向空閑一側(cè)移動所需的大小,這種方式叫做“指針碰撞”
2)對于不規(guī)整對堆內(nèi)存桨醋,虛擬機會維護一個空閑內(nèi)存列表棚瘟,當需要分配內(nèi)存時,劃分出一塊足夠的空間并且更新空閑列表喜最,這種方式叫做“空閑列表”
至于堆內(nèi)存是否規(guī)整連續(xù)偎蘸,取決于具體的垃圾收集器(主要取決于是否帶有compact功能)
由于對象的創(chuàng)建是一個十分頻繁的過程,在并發(fā)情況下會有并發(fā)安全的問題瞬内。解決的方式有兩種:
1)對內(nèi)存分配進行同步處理迷雪,實際上虛擬機采用CAS的方式保證原子性
2)另一種方式是把內(nèi)存分配的動作按照線程進行隔離,即每個線程會預先分配一小塊內(nèi)存虫蝶,稱為本地線程分配緩沖(Thread Local Allocation Buffer振乏,TLAB)。只有在TLAB用完需要新分配的時候在采取同步處理
#初始化零值
內(nèi)存分配完畢后秉扑,虛擬機會對該內(nèi)存區(qū)域初始化零值慧邮,如果是TLAB方式调限,這一步可以提前到TLAB階段。這一步保證了對象實例屬性的初始化误澳。這也就是為什么對象的實例屬性可以不賦初值就能夠直接訪問
#對象頭設置
接下來耻矮,虛擬機需要將對象進行一些設置,將類的元數(shù)據(jù)忆谓、哈希碼裆装、GC分代信息等設置到對象頭中
#對象初始化
執(zhí)行完上述步驟后,對象的實例屬性還都是零值倡缠,下面會執(zhí)行<init>方法哨免,按照程序的意圖對對象進行初始化(我的理解是執(zhí)行構(gòu)造方法)。之后在將對象的引用入棧昙沦。至此琢唾,對象的創(chuàng)建過程結(jié)束
2.對象的內(nèi)存布局
在HotSpot虛擬機當中,對象的內(nèi)存布局分為三個區(qū)域:對象頭盾饮、實例數(shù)據(jù)采桃、對齊填充
#對象頭
對象頭主要存儲兩部分信息,一部分是對象的運行時數(shù)據(jù)(如哈希碼丘损、GC分代信息普办、鎖狀態(tài)標志、線程持有的鎖徘钥、偏向線程ID衔蹲、偏向時間戳等),另一部分是類型指針(即指向類元數(shù)據(jù)的指針呈础,代表該對象是哪個類的實例踪危。當然類的元數(shù)據(jù)也并不一定要存儲在對象頭,這個后續(xù)再討論)
#實例數(shù)據(jù)
實例數(shù)據(jù)部分用于存儲對象實例的數(shù)據(jù)猪落,即實例屬性的內(nèi)容,父類的屬性也會記錄下來畴博。存儲順序會受到虛擬機的分配策略以及字段的定義順序的影響笨忌。默認的分配策略大致有幾點規(guī)則:
1)會將相同寬度的屬性分配在一起
2)滿足1的前提下,父類中的屬性出現(xiàn)在子類前
3)CompactFields參數(shù)為true的時候俱病,會將子類中寬度較窄的屬性插入到父類屬性的空隙之中
#對齊填充
由于HotSpot虛擬機要求對象的其實地址必須是8字節(jié)的整數(shù)倍官疲,因此對于對象大小不是8字節(jié)整數(shù)倍的對象,會被對齊填充
3.對象的訪問定位
對象的訪問解決的是如何通過棧中對象的引用訪問到堆中實際對象的問題亮隙,目前主流的方式有兩種:
1)句柄訪問途凫,棧中對象的引用存儲的是對象的句柄地址(句柄在句柄池中維護),句柄存儲了堆中對象實例的地址以及方法區(qū)中對象的類型數(shù)據(jù)的地址溢吻。
這種方式的優(yōu)點是引用中存儲的是穩(wěn)定的句柄维费,當對象地址變化的時候(GC過程中可能會移動對象實例)果元,只需要更新句柄,不需要更新引用犀盟;缺點也顯而易見而晒,訪問對象時多一次指針操作
2)直接指針訪問,棧中對象的引用存儲的就是對象實例的地址阅畴,對象實例(對象頭)中又存儲了方法區(qū)中對象的類型數(shù)據(jù)的地址
這種方式的優(yōu)點就是訪問迅速(比前者少一次指針操作)倡怎,在HotSpot虛擬機中采用此種方式
思維導圖:
筆記1結(jié)束