一、概念解釋:
1、JVM
Java Virtual Machine,Java語(yǔ)言解釋器,俗稱虛擬機(jī)。負(fù)責(zé)內(nèi)存的分配(堆棧內(nèi)存)、回收(GC)、解析class為硬件運(yùn)行的機(jī)器碼
2、JMM
Java Memory Modal,Java內(nèi)存模型。定義了Java虛擬機(jī)(JVM)在計(jì)算機(jī)內(nèi)存(RAM)中的工作方式,線程之間內(nèi)存刷新的關(guān)系,是隸屬于JVM的。
簡(jiǎn)單來(lái)說(shuō),JVM可以理解為Java執(zhí)行的一個(gè)操作系統(tǒng),而操作系統(tǒng)的模型就是JMM。
二、Java內(nèi)存區(qū)域
Java虛擬機(jī)(JVM)管理的內(nèi)存分為五大區(qū)域。

1、五大內(nèi)存區(qū)域
1 .1、程序計(jì)數(shù)器
程序計(jì)數(shù)器是一塊很小的內(nèi)存空間,是線程私有的,可以認(rèn)為是當(dāng)前線程的行號(hào)指示器。
對(duì)于一個(gè)處理器(如果是多核cpu那就是一核),在一個(gè)確定的時(shí)刻只會(huì)執(zhí)行一條線程指令。一條線程有多個(gè)指令,為了線程切換可以恢復(fù)到正確的執(zhí)行位置,每個(gè)線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器。不同線程間的程序計(jì)數(shù)器互不影響,獨(dú)立存儲(chǔ)。
注意:如果線程執(zhí)行的是個(gè)java方法,那么計(jì)數(shù)器記錄虛擬機(jī)字節(jié)碼指令的地址。如果為native(底層方法),那么計(jì)數(shù)器為空。這塊內(nèi)存區(qū)域是虛擬機(jī)規(guī)范中唯一沒(méi)有OutOfMemoryError的區(qū)域。
1.2、Java棧(虛擬機(jī)棧)
也是線程私有,生命周期與線程相同,就是我們平時(shí)說(shuō)的棧。棧描述的是Java方法執(zhí)行的內(nèi)存模型。
每個(gè)方法被執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、方法出口等信息。每一個(gè)方法被調(diào)用的過(guò)程就對(duì)應(yīng)一個(gè)棧幀在虛擬機(jī)中從入棧到出棧的過(guò)程。
棧幀:是用來(lái)存儲(chǔ)數(shù)據(jù)和部分過(guò)程結(jié)果的數(shù)據(jù)結(jié)構(gòu)。
棧幀的位置:內(nèi)存->運(yùn)行時(shí)數(shù)據(jù)區(qū)->某個(gè)線程對(duì)應(yīng)的虛擬機(jī)棧->here
棧幀大小的確定時(shí)間:編譯期確定,不受運(yùn)行期數(shù)據(jù)影響
有人將java內(nèi)存區(qū)分為棧和堆,因?yàn)榕c對(duì)象內(nèi)存分配關(guān)系最密切的是這兩個(gè)。平時(shí)說(shuō)的棧一般指局部變量表部分。
局部變量表是一片連續(xù)的內(nèi)存空間,用來(lái)存放方法參數(shù),已經(jīng)方法內(nèi)定義的局部變量。存放著編譯期間已知的數(shù)據(jù)類型(八大基本類型和對(duì)象引用類型(reference類型),returnAddress類型)。它的最小的局部變量表空間單位為slot,虛擬機(jī)沒(méi)有指明slot的大小。但在jvm中,long和double類型數(shù)據(jù)明確規(guī)定為64位,這兩個(gè)類型占兩個(gè)slot,其它基本類型固定占用1個(gè)slot。
reference類型:與基本類型不同的是它不等同本身,即使是string,內(nèi)部也是char數(shù)組組成,它可能指向一個(gè)對(duì)象起始位置指針,也可能指向一個(gè)代表對(duì)象的句柄或其它與改對(duì)象有關(guān)的位置。
returnAddress類型:指向一條字節(jié)碼指令的地址
需要注意的是,局部變量表所需的內(nèi)存空間在編譯期完成分配,當(dāng)進(jìn)入一個(gè)方法時(shí),這個(gè)方法在棧中需要分配多大的局部變量空間完全是確定的,在方法運(yùn)行期間不會(huì)改變局部變量表大小。
Java虛擬機(jī)??赡軙?huì)出現(xiàn)兩種類型的異常:
1、線程請(qǐng)求的棧深度大于虛擬機(jī)允許的棧深度,將拋出StackOverflowError。
2、虛擬機(jī)棧空間可以動(dòng)態(tài)擴(kuò)展,當(dāng)動(dòng)態(tài)擴(kuò)展無(wú)法申請(qǐng)到足夠的空間時(shí),拋出OutOfMemory異常。
1.3、本地方法棧
本地方法棧是與虛擬機(jī)棧發(fā)揮的作用十分相似,區(qū)別是虛擬機(jī)棧指向的是Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則為虛擬機(jī)使用到的native方法服務(wù)。
1.4、堆
對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō),堆是Java虛擬機(jī)管理內(nèi)存最大的一塊內(nèi)存區(qū)域,因?yàn)槎汛娣诺膶?duì)象是線程共享的,所以多線程的時(shí)候也需要同步機(jī)制,需要重點(diǎn)了解下。
Java虛擬機(jī)規(guī)范對(duì)這塊的描述是:所有對(duì)象實(shí)例及數(shù)組都要在堆上分配內(nèi)存,但隨著JIT編譯器的發(fā)展和逃逸分析技術(shù)的成熟,這個(gè)說(shuō)法也不受那么絕對(duì),但大多數(shù)情況是這樣的。
1.5、方法區(qū)
方法去同堆一樣,是所有線程共享堆內(nèi)存區(qū)域,為了區(qū)分堆,又稱為非堆。
用于儲(chǔ)存已被虛擬機(jī)加載堆類信息、常量、靜態(tài)變量,如static修飾堆變量加載類堆時(shí)候就被加載到方法區(qū)中。
運(yùn)行時(shí)常量池是方法區(qū)的一部分,class文件除了有類的字段、接口、方法等描述信息之外,還有常量池用于存放編譯期間生成的各種字面量和符號(hào)引用。
基本類型數(shù)據(jù)和引用類型數(shù)據(jù)的存儲(chǔ)位置
有個(gè)經(jīng)典的面試題:‘java中的基本數(shù)據(jù)類型一定存儲(chǔ)在棧中的嗎?’,這句話肯定是錯(cuò)誤的。數(shù)據(jù)是存在棧中還是存在堆中,取決于類型在何處聲明:
在方法中聲明變量,局部變量
聲明基本類型變量——變量名,變量值存在Java虛擬機(jī)棧內(nèi)存中
聲明引用類型變量——變量名在Java虛擬機(jī)棧內(nèi)存中,變量值存在堆內(nèi)存中
在類中聲明變量,全局變量
聲明基本類型變量——變量名,變量值存在堆內(nèi)存中
聲明引用類型變量——變量名,變量值存在堆內(nèi)存中
2、對(duì)象的內(nèi)存布局
JDK1.6采用的是HotSpot虛擬機(jī),對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為三塊區(qū)域:1、對(duì)象頭(Header)2、實(shí)例數(shù)據(jù)(Instance Data)3、對(duì)齊填充(Padding)

3、對(duì)象的訪問(wèn)定位
Java程序需要通過(guò)引用(ref)數(shù)據(jù)來(lái)操作堆上面的對(duì)象,那么如何通過(guò)引用定位、訪問(wèn)到對(duì)象的具體位置。
3.1、句柄訪問(wèn)
簡(jiǎn)單來(lái)說(shuō)就是Java堆劃出一塊內(nèi)存作為句柄池,引用中存儲(chǔ)對(duì)象的句柄地址,句柄中含對(duì)象實(shí)例數(shù)據(jù)、類型數(shù)據(jù)的地址信息。
優(yōu)點(diǎn):引用中存儲(chǔ)的是穩(wěn)定的句柄地址,在對(duì)象被移動(dòng)【垃圾收集時(shí)移動(dòng)對(duì)象是常態(tài)】只需改變句柄中實(shí)例數(shù)據(jù)的指針,不需要改動(dòng)引用【ref】本身。

3.2、直接指針
與句柄訪問(wèn)不同的是,ref中直接存儲(chǔ)的就是對(duì)象的實(shí)例數(shù)據(jù),但是類型數(shù)據(jù)跟句柄訪問(wèn)方式一樣
優(yōu)點(diǎn):優(yōu)勢(shì)很明顯,就是速度快,相比句柄訪問(wèn)少了一次指針定位的開銷時(shí)間?!究赡苁浅鲇贘ava中對(duì)象的訪問(wèn)十分頻繁,平時(shí)我們常用的JVM HotSpot采用此種方式】

參考文章:
1、什么Java內(nèi)存模型
2、Java虛擬機(jī)運(yùn)行時(shí)棧幀結(jié)構(gòu)
3、怎么理解returnAddress
4、參考逃逸分析
5、idea設(shè)置相關(guān)內(nèi)存大小設(shè)置
6、Java對(duì)象訪問(wèn)定位
7、深入理解JVM-內(nèi)存模型(jmm)和GC
8、android 多線程 — java 內(nèi)存模型