JVM內存模型/內存空間:運行時數(shù)據(jù)區(qū)
JVM內存模型/內存空間
Java虛擬機JVM運行起來,就會給內存劃分空間,這塊空間成為運行時數(shù)據(jù)區(qū)。
運行時數(shù)據(jù)區(qū)主要劃分為以下 6個 :

① 程序計數(shù)器 (Program Counter Register)
- 一塊較小的內存空間,可以看作是當前線程所執(zhí)行的字節(jié)碼的行號指示器
- 線程私有的內存
- 值得注意的是:《Java虛擬機規(guī)范》中,唯一一個沒有規(guī)定任何OutOfMemoryError情況的區(qū)域?。。?/li>
程序計數(shù)器也可以稱為PC寄存器,通俗的講就是指令緩存,它主要用來緩存當前程序執(zhí)行的下一條指令的地址,CPU根據(jù)這個地址找到將要執(zhí)行的指令。這個寄存器是JVM內部實現(xiàn)的,不是物理概念上的計數(shù)器,不過和JVM的實現(xiàn)邏輯一樣。
② Java虛擬機棧 (VM Stack)
- Java方法執(zhí)行的線程內存模型
- 每一個線程運行起來的都會對應一個棧(線程棧),棧中的數(shù)據(jù)是該線程獨有的,不會產生資源共享的情況,因此線程棧是線程安全的。
- 棧當中存放的是棧幀
- 每個Java方法的執(zhí)行對應著一個棧幀的進棧和出棧的操作
- 當線程調用方法時,就形成一個棧幀,并將這個棧幀進行壓棧操作,方法執(zhí)行完之后進行出棧操作。
- 這個棧幀中包括:局部變量、操作數(shù)棧、指向當前方法對應類的常量池引用、方法返回地址等信息
- 為虛擬機執(zhí)行Java方法(也就是字節(jié)碼)服務
- 線程私有的內存
- 其生命周期與線程相同
- 兩類異常:
- 如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常
- 如果JVM棧容量可以動態(tài)擴展,當棧擴展時無法申請到足夠的內存時,會拋出OutOfMemoryError異常
③ 本地方法棧 (Native Method Stack)
區(qū)別于 “Java虛擬機?!?nbsp;
- 本地方法棧只為虛擬機使用到的本地(Native)方法服務,為其運行提供內存環(huán)境
- 本地方法是指JVM需要調用非Java語言所實現(xiàn)的方法,例如C/C++/C#
- JVM棧運行的是Java方法
在JVM規(guī)范中,沒有強化性要求實現(xiàn)方一定要劃分出本地方法棧(例如:HotSpot虛擬機將本地方法棧和棧合二為一)和具體實現(xiàn)(不同的操作系統(tǒng),對JVM規(guī)范的具體實現(xiàn)都不一樣)。
- 同 “Java虛擬機?!?nbsp;一樣,本地方法棧也有兩類異常:
- 棧深度溢出時,將拋出StackOverflowError異常
- 棧擴展失敗時,會拋出OutOfMemoryError異常
④ Java堆 (Java Heap)
- 虛擬機所管理的內存中最大的一塊
- Java堆是被所有線程共享的一塊內存區(qū)域
- 唯一的目的:存放對象示例。
- Java中 “幾乎” 所有的對象實例都在這里分配內存;
- 但是,由于現(xiàn)在技術發(fā)展,說 “Java對象示例都分配在堆上” 也漸漸變得不是那么絕對了。
- Java堆是垃圾收集器管理的內存區(qū)域,也稱“GC堆”。
- 堆內存中的對象沒有被引用,會自動被Java的垃圾回收機制回收。
- 當在方法中定義了局部變量:
- 如果局部變量是基本數(shù)據(jù)類型,直接存放在棧內存中;
- 如果局部變量是引用數(shù)據(jù)類型,會將變量值存放在堆內存中,棧內存中只存放引用地址。
- Java堆可以處于物理上不連續(xù)的內存空間,但在邏輯上它應該是被視為連續(xù)的。
- 如果在Java堆中沒有內存完成實例分配,并且Java堆也無法再擴展時,Java虛擬機將會拋出OutOfMemoryError異常
⑤ 方法區(qū)(Method Area)
- 和 “Java堆” 一樣,是被所有線程共享的一塊區(qū)域。
- 主要存放每一個被加載的class的信息
class信息主要包含魔數(shù)(確定是否是一個class文件),常量池,訪問標志(當前的類是普通類還是接口,是否是抽象類,是否被public修飾,是否使用了final修飾等描述信息…),字段表集合信息(使用什么訪問修飾符,是實例變量還是靜態(tài)變量,是否使用了final修飾等描述信息…),方法表集合信息(使用什么訪問修飾符,是否靜態(tài)方法,是否使用了 final 修飾,是否使用了synchronized修飾,是否是native方法…)等內容。
當一個類加載器加載了一個類的時候,會根據(jù)這個class文件創(chuàng)建一個class對象,class對象就包含了上述的信息。后續(xù)要創(chuàng)建這個類的實例,都根據(jù)這個class對象創(chuàng)建出來的。
在《Java虛擬機規(guī)范》中,把方法區(qū)描述為堆的一個邏輯部分,但是它卻有一個別名叫作 “非堆” ,目的是與Java堆區(qū)分開來。
如果方法區(qū)無法滿足新的內存分配需求時,將拋出OutOfMemoryError異常
⑥ 運行時常量池 (Running Constant Pool)
- 運行時常量池是方法區(qū)的一部分。
- 存放class中最重要的資源,JVM為每一個class對象都維護著一個常量池。
- 常量池表:用于存放編譯期生成的各種字面量與字符引用。
- 這部分內容將在類加載后存放到方法區(qū)的運行時常量池中。
- 運行時常量池相對Class文件常量池的一個重要特征是具備動態(tài)性。
- 當常量池無法再申請到內存時,會拋出OutOfMemoryError異常
【特】 直接內存
運行時數(shù)據(jù)區(qū)主要為以上6個區(qū)域,但是JVM所管理的還有一個較特殊的區(qū)域:
- 直接內存 (Direct Memory)
- 既不是虛擬機運行時數(shù)據(jù)區(qū)的一部分,也不是《Java虛擬機規(guī)范》中定義的內存區(qū)域。
- 但是這部分內存區(qū)域也被頻繁地使用,而且也可能導致OutOfMemoryError異常出現(xiàn)
1.在JDK 1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的I/O方式,它可以使用Native函數(shù)庫 直接分配堆外內存,然后通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因為避免了在Java堆和Native堆中來回復制數(shù)據(jù)。
2.在本機直接內存的分配不會受到Java堆大小的限制,但是,既然是內存,則肯定還是會受到本機總內存(包括RAM及SWAP區(qū)或者分頁文件)的大小及處理器尋址空間的限制。服務器管理員配置虛擬機參數(shù)時,一般會根據(jù)實際內存設置-Xmx等參數(shù)信息,但經(jīng)常會忽略掉直接內存,使得各個內存區(qū)域的總和大于物理內存限制(包括物理上的和操作系統(tǒng)級的限制),從而導致動態(tài)擴展時出現(xiàn)OutOfMemoryError異常。
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
Springboot Autowried及Resouce使用對比解析
這篇文章主要介紹了Springboot Autowried及Resouce使用對比解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06
SpringMVC參數(shù)傳遞之基本數(shù)據(jù)類型和復雜對象說明
這篇文章主要介紹了SpringMVC參數(shù)傳遞之基本數(shù)據(jù)類型和復雜對象說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
Java?+?Selenium?+?OpenCV解決自動化測試中的滑塊驗證問題
OpenCV是一個基于Apache2.0許可(開源)發(fā)行的跨平臺計算機視覺和機器學習軟件庫,可以運行在Linux、Windows、Android和Mac?OS操作系統(tǒng)上,這篇文章主要介紹了Java?+?Selenium?+?OpenCV解決自動化測試中的滑塊驗證,需要的朋友可以參考下2022-07-07

