本文為 《深入理解Java虛擬機》第二章內(nèi)容的學(xué)習(xí)筆記,部分內(nèi)容經(jīng)過二次加工泡挺。若對相關(guān)知識感興趣,推薦購書深入閱讀命浴。若認(rèn)為文章涉嫌侵權(quán)娄猫,請聯(lián)系作者及時刪除贱除。
本作品采用 知識共享署名-非商業(yè)性使用-相同方式共享 3.0 中國大陸許可協(xié)議 (CC BY-NC-SA 3.0 CN) 進行許可 。非商業(yè)性質(zhì)轉(zhuǎn)載請注明作者和出處媳溺,禁止商業(yè)性質(zhì)轉(zhuǎn)載月幌。
開源創(chuàng)造世界
個人練習(xí)代碼:https://github.com/dreamerfable/Understanding-the-JVM
運行時數(shù)據(jù)區(qū)域
根據(jù) JVM規(guī)范,Java虛擬機鎖管理的內(nèi)存包括以下幾個運行時區(qū)域
各線程獨立存儲褂删,互不影響的內(nèi)存飞醉,稱作線程私有的內(nèi)存
Program Counter Register
程序計數(shù)器是一塊較小的內(nèi)存空間,可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器屯阀,分支缅帘、循環(huán)、跳轉(zhuǎn)难衰、異常處理等基礎(chǔ)功能都需要依賴它完成
線程私有
這個區(qū)域不存在OutOfMemoryError情況
Virtual Machine Stack
虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型钦无,每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀 Stack Frame,用于存儲局部變量表盖袭、操作數(shù)棧失暂、動態(tài)鏈接、方法出口等信息鳄虱。每一個方法調(diào)用直至執(zhí)行完成的過程弟塞,對應(yīng)著一個棧幀在虛擬機棧中入棧到出棧的過程拙已。
線程私有
如果線程請求的棧深度大于虛擬機所允許的深度决记,拋出StackOverflowError
如果虛擬機棧可以動態(tài)擴展倍踪,擴展時如果無法申請到足夠的內(nèi)存系宫,拋出OutOfMemoryError異常
Native Method Stack
本地方法棧與VM Stack作用類似。不同的是建车,VM Stack 為虛擬機執(zhí)行Java方法服務(wù)扩借,而本地方法棧為虛擬機使用到的Native方法服務(wù)。
虛擬機規(guī)范對本地方法棧沒有強制規(guī)定缤至,部分虛擬機把本地方法棧與虛擬機棧合二為一潮罪,如HotSpot
會拋出StackOverflowError和OutOfMemoryError。
Heap
堆领斥,是被所有線程共享的一塊內(nèi)存區(qū)域错洁,在虛擬機啟動時創(chuàng)建。用于存放對象實例戒突,幾乎所有對象實例都在這里分配內(nèi)存。
堆是垃圾收集器管理的主要區(qū)域描睦。從內(nèi)存回收角度看膊存,由于現(xiàn)在收集器基本都采用分代收集算法,所以堆可以細(xì)分為:新生代、老年代隔崎;再細(xì)致可以分為Eden空間今艺、From Survivor空間、To Survivor空間等爵卒。
在堆中沒有內(nèi)存完成實例分配虚缎,并且堆也無法再擴展時,拋出OutOfMemoryError異常钓株。
Method Area
方法區(qū)也是被所有線程共享的內(nèi)存區(qū)域实牡,用于存儲已被虛擬機加載的類信息、常量轴合、靜態(tài)變量创坞、即時編譯器編譯后的代碼等。
JVM規(guī)范將其描述為堆的一個邏輯部分受葛,但其別名為 Non-Heap题涨,用來將其與堆加以區(qū)分。
根據(jù)JVM規(guī)范总滩,當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時纲堵,將拋出OutOfMemoryError異常。
Runtime Constant Pool
運行時常量池用于存放Class文件中的常量池
常量池 Constant Pool Table 在Class文件中用于存放編譯期生成的各種字面量和符號引用闰渔,這部分內(nèi)容在類加載后會進入Method Area的運行時常量池席函。
運行時常量池除了保存Class文件中描述的符號引用外,還會把翻譯出來的直接引用也存儲下來澜建。另外向挖,運行時常量池相比較于Class文件常量池具有動態(tài)性,可以保存運行時產(chǎn)生的常量炕舵。
無法再申請到內(nèi)存時拋出OutOfMemoryError異常何之。
Direct Memory
直接內(nèi)存 不是虛擬機運行時數(shù)據(jù)區(qū)的一部分,也不是JVM規(guī)范中定義的內(nèi)存區(qū)域咽筋。但這部分同樣被頻繁的使用溶推,而且也可能導(dǎo)致OutOfMemoryError異常出現(xiàn)。
JDK1.4中新加入的NIO類奸攻,引入了一種基于通道 Channel 與 緩沖區(qū) Buffer 的 I/O方式蒜危,它可以使用Native函數(shù)庫直接分配堆外內(nèi)存,然后通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作睹耐。這樣能在一些場景中顯著提高性能辐赞,因為避免了在Java堆和Native堆中來回復(fù)制數(shù)據(jù)。
本季直接內(nèi)存的分配不會受到Java堆大小的限制硝训,但是其受到本機總內(nèi)存大小以及處理器尋址空間的限制响委,可能會導(dǎo)致動態(tài)擴展時出現(xiàn)OutOfMemoryError異常新思。