JVM內(nèi)存模型/內(nèi)存空間:運(yùn)行時(shí)數(shù)據(jù)區(qū)
JVM內(nèi)存模型/內(nèi)存空間
Java虛擬機(jī)JVM運(yùn)行起來,就會(huì)給內(nèi)存劃分空間,這塊空間成為運(yùn)行時(shí)數(shù)據(jù)區(qū)。
運(yùn)行時(shí)數(shù)據(jù)區(qū)主要?jiǎng)澐譃橐韵?nbsp;6個(gè) :
① 程序計(jì)數(shù)器 (Program Counter Register)
- 一塊較小的內(nèi)存空間,可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器
- 線程私有的內(nèi)存
- 值得注意的是:《Java虛擬機(jī)規(guī)范》中,唯一一個(gè)沒有規(guī)定任何OutOfMemoryError情況的區(qū)域!??!
程序計(jì)數(shù)器也可以稱為PC寄存器,通俗的講就是指令緩存,它主要用來緩存當(dāng)前程序執(zhí)行的下一條指令的地址,CPU根據(jù)這個(gè)地址找到將要執(zhí)行的指令。這個(gè)寄存器是JVM內(nèi)部實(shí)現(xiàn)的,不是物理概念上的計(jì)數(shù)器,不過和JVM的實(shí)現(xiàn)邏輯一樣。
② Java虛擬機(jī)棧 (VM Stack)
- Java方法執(zhí)行的線程內(nèi)存模型
- 每一個(gè)線程運(yùn)行起來的都會(huì)對(duì)應(yīng)一個(gè)棧(線程棧),棧中的數(shù)據(jù)是該線程獨(dú)有的,不會(huì)產(chǎn)生資源共享的情況,因此線程棧是線程安全的。
- 棧當(dāng)中存放的是棧幀
- 每個(gè)Java方法的執(zhí)行對(duì)應(yīng)著一個(gè)棧幀的進(jìn)棧和出棧的操作
- 當(dāng)線程調(diào)用方法時(shí),就形成一個(gè)棧幀,并將這個(gè)棧幀進(jìn)行壓棧操作,方法執(zhí)行完之后進(jìn)行出棧操作。
- 這個(gè)棧幀中包括:局部變量、操作數(shù)棧、指向當(dāng)前方法對(duì)應(yīng)類的常量池引用、方法返回地址等信息
- 為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù)
- 線程私有的內(nèi)存
- 其生命周期與線程相同
- 兩類異常:
- 如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常
- 如果JVM棧容量可以動(dòng)態(tài)擴(kuò)展,當(dāng)棧擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存時(shí),會(huì)拋出OutOfMemoryError異常
③ 本地方法棧 (Native Method Stack)
區(qū)別于 “Java虛擬機(jī)?!?nbsp;
- 本地方法棧只為虛擬機(jī)使用到的本地(Native)方法服務(wù),為其運(yùn)行提供內(nèi)存環(huán)境
- 本地方法是指JVM需要調(diào)用非Java語(yǔ)言所實(shí)現(xiàn)的方法,例如C/C++/C#
- JVM棧運(yùn)行的是Java方法
在JVM規(guī)范中,沒有強(qiáng)化性要求實(shí)現(xiàn)方一定要?jiǎng)澐殖霰镜胤椒#ɡ纾篐otSpot虛擬機(jī)將本地方法棧和棧合二為一)和具體實(shí)現(xiàn)(不同的操作系統(tǒng),對(duì)JVM規(guī)范的具體實(shí)現(xiàn)都不一樣)。
- 同 “Java虛擬機(jī)棧” 一樣,本地方法棧也有兩類異常:
- 棧深度溢出時(shí),將拋出StackOverflowError異常
- 棧擴(kuò)展失敗時(shí),會(huì)拋出OutOfMemoryError異常
④ Java堆 (Java Heap)
- 虛擬機(jī)所管理的內(nèi)存中最大的一塊
- Java堆是被所有線程共享的一塊內(nèi)存區(qū)域
- 唯一的目的:存放對(duì)象示例。
- Java中 “幾乎” 所有的對(duì)象實(shí)例都在這里分配內(nèi)存;
- 但是,由于現(xiàn)在技術(shù)發(fā)展,說 “Java對(duì)象示例都分配在堆上” 也漸漸變得不是那么絕對(duì)了。
- Java堆是垃圾收集器管理的內(nèi)存區(qū)域,也稱“GC堆”。
- 堆內(nèi)存中的對(duì)象沒有被引用,會(huì)自動(dòng)被Java的垃圾回收機(jī)制回收。
- 當(dāng)在方法中定義了局部變量:
- 如果局部變量是基本數(shù)據(jù)類型,直接存放在棧內(nèi)存中;
- 如果局部變量是引用數(shù)據(jù)類型,會(huì)將變量值存放在堆內(nèi)存中,棧內(nèi)存中只存放引用地址。
- Java堆可以處于物理上不連續(xù)的內(nèi)存空間,但在邏輯上它應(yīng)該是被視為連續(xù)的。
- 如果在Java堆中沒有內(nèi)存完成實(shí)例分配,并且Java堆也無(wú)法再擴(kuò)展時(shí),Java虛擬機(jī)將會(huì)拋出OutOfMemoryError異常
⑤ 方法區(qū)(Method Area)
- 和 “Java堆” 一樣,是被所有線程共享的一塊區(qū)域。
- 主要存放每一個(gè)被加載的class的信息
class信息主要包含魔數(shù)(確定是否是一個(gè)class文件),常量池,訪問標(biāo)志(當(dāng)前的類是普通類還是接口,是否是抽象類,是否被public修飾,是否使用了final修飾等描述信息…),字段表集合信息(使用什么訪問修飾符,是實(shí)例變量還是靜態(tài)變量,是否使用了final修飾等描述信息…),方法表集合信息(使用什么訪問修飾符,是否靜態(tài)方法,是否使用了 final 修飾,是否使用了synchronized修飾,是否是native方法…)等內(nèi)容。
當(dāng)一個(gè)類加載器加載了一個(gè)類的時(shí)候,會(huì)根據(jù)這個(gè)class文件創(chuàng)建一個(gè)class對(duì)象,class對(duì)象就包含了上述的信息。后續(xù)要?jiǎng)?chuàng)建這個(gè)類的實(shí)例,都根據(jù)這個(gè)class對(duì)象創(chuàng)建出來的。
在《Java虛擬機(jī)規(guī)范》中,把方法區(qū)描述為堆的一個(gè)邏輯部分,但是它卻有一個(gè)別名叫作 “非堆” ,目的是與Java堆區(qū)分開來。
如果方法區(qū)無(wú)法滿足新的內(nèi)存分配需求時(shí),將拋出OutOfMemoryError異常
⑥ 運(yùn)行時(shí)常量池 (Running Constant Pool)
- 運(yùn)行時(shí)常量池是方法區(qū)的一部分。
- 存放class中最重要的資源,JVM為每一個(gè)class對(duì)象都維護(hù)著一個(gè)常量池。
- 常量池表:用于存放編譯期生成的各種字面量與字符引用。
- 這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池中。
- 運(yùn)行時(shí)常量池相對(duì)Class文件常量池的一個(gè)重要特征是具備動(dòng)態(tài)性。
- 當(dāng)常量池?zé)o法再申請(qǐng)到內(nèi)存時(shí),會(huì)拋出OutOfMemoryError異常
【特】 直接內(nèi)存
運(yùn)行時(shí)數(shù)據(jù)區(qū)主要為以上6個(gè)區(qū)域,但是JVM所管理的還有一個(gè)較特殊的區(qū)域:
- 直接內(nèi)存 (Direct Memory)
- 既不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是《Java虛擬機(jī)規(guī)范》中定義的內(nèi)存區(qū)域。
- 但是這部分內(nèi)存區(qū)域也被頻繁地使用,而且也可能導(dǎo)致OutOfMemoryError異常出現(xiàn)
1.在JDK 1.4中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的I/O方式,它可以使用Native函數(shù)庫(kù) 直接分配堆外內(nèi)存,然后通過一個(gè)存儲(chǔ)在Java堆中的DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬嗽贘ava堆和Native堆中來回復(fù)制數(shù)據(jù)。
2.在本機(jī)直接內(nèi)存的分配不會(huì)受到Java堆大小的限制,但是,既然是內(nèi)存,則肯定還是會(huì)受到本機(jī)總內(nèi)存(包括RAM及SWAP區(qū)或者分頁(yè)文件)的大小及處理器尋址空間的限制。服務(wù)器管理員配置虛擬機(jī)參數(shù)時(shí),一般會(huì)根據(jù)實(shí)際內(nèi)存設(shè)置-Xmx等參數(shù)信息,但經(jīng)常會(huì)忽略掉直接內(nèi)存,使得各個(gè)內(nèi)存區(qū)域的總和大于物理內(nèi)存限制(包括物理上的和操作系統(tǒng)級(jí)的限制),從而導(dǎo)致動(dòng)態(tài)擴(kuò)展時(shí)出現(xiàn)OutOfMemoryError異常。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
- JAVA JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)詳解
- 面試時(shí)必問的JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)詳解
- Java JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)(Run-Time Data Areas)
- JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)劃分原理詳解
- Java內(nèi)存模型與JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)的區(qū)別詳解
- JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)原理解析
- Java內(nèi)存模型JMM與volatile
- Java內(nèi)存模型(JMM)及happens-before原理
- JVM?運(yùn)行時(shí)數(shù)據(jù)區(qū)與JMM?內(nèi)存模型
相關(guān)文章
Java并發(fā)之傳統(tǒng)線程同步通信技術(shù)代碼詳解
這篇文章主要介紹了Java并發(fā)之傳統(tǒng)線程同步通信技術(shù)代碼詳解,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02Java用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列的示例
下面小編就為大家?guī)硪黄狫ava用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列的示例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09IDEA 顯示Run Dashboard窗口的2種方式(推薦)
這篇文章主要介紹了IDEA 顯示Run Dashboard窗口的2種方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08springboot配置flyway(入門級(jí)別教程)
本文介紹了springboot配置flyway,主要介紹基于SpringBoot集成flyway來管理數(shù)據(jù)庫(kù)的變更,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09詳解如何在SpringBoot中實(shí)現(xiàn)優(yōu)雅關(guān)閉
這篇文章主要介紹了如何在SpringBoot中實(shí)現(xiàn)優(yōu)雅關(guān)閉,SpringBoot應(yīng)用程序的關(guān)閉可以是崩潰,也可以是手動(dòng)關(guān)閉的,Shutdown、Crash 和 Graceful 之間的區(qū)別在于,它控制決定了我們可以用這個(gè)事件做什么,本文中,一起研究下Spring Boot提供的開箱即用功能之一:優(yōu)雅關(guān)閉2024-09-09