聲明:此篇文章是讀《深入理解JAVA虛擬機》的筆記
??先來一張圖:
程序計數(shù)器(Program Counter Register)
??程序計數(shù)器是一塊較小的內(nèi)存空間闷尿,它的作用可以看做是當前線程所執(zhí)行的字節(jié)碼的行號指示器损痰。需要注意的是土至,JVM虛擬機的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式實現(xiàn)的。為了線程切換后能恢復到正確的執(zhí)行位置啡浊,每條線程都需要有一個獨立的程序計數(shù)器觅够。因此這塊內(nèi)存區(qū)域是線程私有的。Java虛擬機棧(Java Virtual Machine Stacks)
??Java虛擬機棧也是線程私有的巷嚣,它的生命周期與線程相同喘先。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會同時創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表、操作棧廷粒、動態(tài)鏈接窘拯、方法出口等信息。每一個方法被調(diào)用直至執(zhí)行完成的過程坝茎,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程涤姊。
??對這個區(qū)域,Java虛擬機規(guī)范中嗤放,規(guī)定了兩種異常狀況:如果線程請求的棧深度大于虛擬機所允許的深度思喊,將拋出StackOverflowError異常;如果虛擬機棿巫茫可以動態(tài)擴展恨课,當擴展無法申請到足夠的內(nèi)存時會拋出OutOfMemoryError異常。本地方法棧(Native Method Stacks)
??與虛擬機棧所發(fā)揮的作用是非常相似的岳服,區(qū)別不過是虛擬機棧為虛擬執(zhí)行Java方法(字節(jié)碼)服務剂公,而本地方法棧則是為虛擬機使用到的Native方法服務。Java堆(Java Heap)
??Java堆是java虛擬機所管理的內(nèi)在中最大的一塊吊宋,是被所有線程共享的一塊內(nèi)在區(qū)域诬留。虛擬機啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象的實例,幾乎所有的對象實例都在這里分配內(nèi)存文兑。
??Java堆是垃圾收集管理的主要區(qū)域,因此很多時候也被稱做GC堆(Garbage Collected Heap)腺劣。
??Java堆可以處于物理上不連續(xù)的內(nèi)存空間中绿贞,只要邏輯上是連續(xù)的即可。在實現(xiàn)時可以是固定的大小橘原,也可以是擴展的籍铁,當前主流虛擬機都是按照可擴展來實現(xiàn)的(通過-Xmx和-Xms來控制)。
??如果在堆中沒有內(nèi)存完成實例分配趾断,并且堆也無法再擴展時拒名,將會拋出OutOfMemoryError異常。方法區(qū)(Method Area)
??方法區(qū)和Java堆一樣芋酌,是各個線程共享的內(nèi)存區(qū)域增显,它用于存儲已被虛擬機加載的類信息、常量脐帝、靜態(tài)變量同云、即時編譯器編譯后的代碼等數(shù)據(jù)。
??Java虛擬機規(guī)范把方法區(qū)描述為堆的一個邏輯部分堵腹,但是它卻有一個別名Non-Heap(非堆)炸站,目的應該是與Java堆區(qū)分。
??根據(jù)Java虛擬機規(guī)范疚顷,當方法區(qū)無法滿足內(nèi)在分配需求時旱易,將拋出OutOfMemoryError異常。
??注: 在HotSpot虛擬機上開發(fā)和部署的程序的程序員腿堤,很多人把方法區(qū)稱為“永久代(Permanent Generation)”阀坏,兩者本質(zhì)上并不等價,只是因為HotSpot虛擬機的設計團隊選擇把GC分代收集擴展至方法區(qū)释液,或者說使用永久代來實現(xiàn)方法區(qū)而已全释。
運行時常量(Runtime Constant Pool)
??運行時常量是方法區(qū)的一部分。Class文件中除了有類的版本误债、字段浸船、方法、接口描述等信息外寝蹈,還有一項信息是常量池李命,用于存放編譯期生成的各種字面量和符號引用,這部分的內(nèi)容將在類加載后存放在方法區(qū)的運行時常量池中箫老。
??運行時常量池具備動態(tài)性封字,Java語言并不要求常量一定只能在編譯期產(chǎn)生,也就是并非預置入Class文件中常量池的內(nèi)容才能進入方法區(qū),運行期間也可能將新的常量放入池中阔籽。比如:String類的intern()方法流妻。
??運行時常量池是方法區(qū)的一部分,當常量池無法再申請到內(nèi)在時會拋出OutOfMemoryError異常笆制。直接內(nèi)存(Direct Memory)
??直接內(nèi)存并不是虛擬機運行時數(shù)據(jù)區(qū)的一部分绅这,也不是Java虛擬機規(guī)范中定義的內(nèi)存區(qū)域。
??在JDK1.4中新加入NIO(New Input/Output)類在辆,引用了一種基于通道(Channel)與緩沖區(qū)(Buffer)的I/O方式证薇,它可以使用Native函數(shù)庫直接分配堆外內(nèi)存,然后通過一個存儲在Java堆里面的DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作匆篓。
??直接內(nèi)存的分配不會受到Java堆大小的限制浑度,但是會受到本機總內(nèi)存(RAM及SWAP)的大小 及處理器尋址空間的限制。在分配虛擬機參數(shù)時鸦概,如果各個內(nèi)存區(qū)域的總和大于物理內(nèi)存的限制箩张,動態(tài)擴展時也會導致OutOfMemoryError異常。