JVM 內(nèi)存區(qū)域劃分如圖所示耿戚,從圖中我們可以看出:
- JVM 堆中的數(shù)據(jù)是共享的湿故,是占用內(nèi)存最大的一塊區(qū)域阿趁。
- 可以執(zhí)行字節(jié)碼的模塊叫作執(zhí)行引擎。
- 執(zhí)行引擎在線程切換時(shí)怎么恢復(fù)坛猪?依靠的就是程序計(jì)數(shù)器脖阵。
- JVM 的內(nèi)存劃分與多線程是息息相關(guān)的。像我們程序中運(yùn)行時(shí)用到的棧墅茉,以及本地方法棧命黔,它們的維度都是線程。
虛擬機(jī)棧:
- Java 虛擬機(jī)棧是基于線程的就斤。哪怕你只有一個(gè) main() 方法悍募,也是以線程的方式運(yùn)行的。在線程的生命周期中洋机,參與計(jì)算的數(shù)據(jù)會(huì)頻繁地入棧和出棧坠宴,棧的生命周期是和線程一樣的。棧里的每條數(shù)據(jù)绷旗,就是棧幀喜鼓。在每個(gè) Java 方法被調(diào)用的時(shí)候,都會(huì)創(chuàng)建一個(gè)棧幀衔肢,并入棧庄岖。可以理解為每個(gè)方法開(kāi)辟一個(gè)獨(dú)立的棧幀角骤,這個(gè)棧幀里的局部變量不受其他棧幀的影響隅忿。這條線程開(kāi)辟的虛擬機(jī)棧內(nèi)存大小是所有的棧幀開(kāi)辟的大小總和。
程序計(jì)數(shù)器
- 程序計(jì)數(shù)器是一塊較小的內(nèi)存空間启搂,它的作用可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器硼控。這里面存的,就是當(dāng)前線程執(zhí)行的進(jìn)度胳赌。在多線程任務(wù)中牢撼,cup在線程之間進(jìn)行切換需要記錄線程執(zhí)行到哪了,等到線程重新分配到cpu時(shí)才能在上次執(zhí)行的地方繼續(xù)執(zhí)行下去疑苫。
堆
- JVM 上最大的內(nèi)存區(qū)域熏版,我們申請(qǐng)的幾乎所有的對(duì)象,都是在這里存儲(chǔ)的捍掺。我們常說(shuō)的垃圾回收撼短,操作的對(duì)象就是堆。jvm堆空間大小可以指定挺勿,在啟動(dòng)時(shí)就會(huì)從系統(tǒng)內(nèi)存中分配曲横,分配的堆內(nèi)存不一定全部會(huì)被用到。就好像一個(gè)公司包了電影院的三排座位,但是實(shí)際公司去了多少人不一定禾嫉,但是這三排位置是預(yù)留給公司的人的灾杰,不是公司的人不能夠使用。隨著對(duì)象的頻繁創(chuàng)建熙参,堆空間占用的越來(lái)越多艳吠,就需要不定期的對(duì)不再使用的對(duì)象進(jìn)行回收。這個(gè)在 Java 中孽椰,就叫作 GC(Garbage Collection)昭娩。對(duì)象在堆中被創(chuàng)建的時(shí)候大小是固定的,這里涉及到位置分配的問(wèn)題黍匾,我們?cè)儆秒娪霸簣?chǎng)景模擬栏渺。計(jì)算機(jī)只能識(shí)別0和1,數(shù)據(jù)在內(nèi)存中實(shí)際上是一連串的0和1锐涯,一個(gè)對(duì)象時(shí)一連串的0和1迈嘹,當(dāng)對(duì)象比較大的時(shí)候,這串?dāng)?shù)字就比較長(zhǎng)全庸,保存在內(nèi)存中占的位置也就比較長(zhǎng)秀仲,好比我們?nèi)齻€(gè)人去電影院看電影。作為電影院分配位置的方案壶笼,比較好的就是三個(gè)人坐一塊神僵,按順序坐(1,2覆劈,3號(hào)位置)保礼。新來(lái)的人繼續(xù)往后面,如果來(lái)兩個(gè)就分配(4责语,5號(hào))位置炮障,如果來(lái)三個(gè)就分配(4,5坤候,6號(hào))位置胁赢,把整個(gè)電影院劃分為兩個(gè)區(qū)域(已使用區(qū)域和未使用區(qū)域),不管已使用區(qū)域的人是否離開(kāi)白筹,新來(lái)的人安排去未使用區(qū)域智末,這種方案好處時(shí)管理方便,安排入座快徒河,壞處就是如果有人中途離開(kāi)系馆,那對(duì)應(yīng)的位置就空了下來(lái)不能利用,浪費(fèi)了空間顽照,對(duì)應(yīng)內(nèi)存中的內(nèi)存碎片由蘑。
元空間
- 在 Java 8 之前,類的信息是放在一個(gè)叫 Perm (永久代)區(qū)的內(nèi)存里面的。更早版本(java7之前)尼酿,甚至 String.intern 相關(guān)的運(yùn)行時(shí)常量池也放在這里下隧。這個(gè)區(qū)域有大小限制,很容易造成 JVM 內(nèi)存溢出谓媒,從而造成 JVM 崩潰。Perm 區(qū)在 Java 8 中已經(jīng)被徹底廢除何乎,取而代之的是 Metaspace句惯。原來(lái)的 Perm 區(qū)是在堆上的,現(xiàn)在的元空間是在非堆上的支救,這是背景抢野。
元空間的好處也是它的壞處。使用非堆可以使用操作系統(tǒng)的內(nèi)存各墨,JVM 不會(huì)再出現(xiàn)方法區(qū)的內(nèi)存溢出指孤;但是,無(wú)限制的使用會(huì)造成操作系統(tǒng)的死亡贬堵。所以恃轩,一般也會(huì)使用參數(shù) -XX:MaxMetaspaceSize 來(lái)控制大小。
方法區(qū)黎做,作為一個(gè)概念叉跛,依然存在。它的物理存儲(chǔ)的容器蒸殿,就是 Metaspace筷厘。我們將在后面的課時(shí)中,再次遇到它『晁現(xiàn)在酥艳,你只需要了解到,這個(gè)區(qū)域存儲(chǔ)的內(nèi)容爬骤,包括:類的信息充石、常量池、方法數(shù)據(jù)霞玄、方法代碼就可以了赫冬。
本地方法棧
- 本地方法棧(Native Method Stacks)與 Java 虛擬機(jī)棧所發(fā)揮的作用是非常相似的,其區(qū)別不過(guò)是虛擬機(jī)棧為虛擬機(jī)執(zhí)行 Java 方法(也就是字節(jié)碼)服務(wù)溃列,而本地方法棧則是為虛擬機(jī)使用到的 Native 方法服務(wù)劲厌。虛擬機(jī)規(guī)范中對(duì)本地方法棧中的方法使用的語(yǔ)言、使用方式與數(shù)據(jù)結(jié)構(gòu)并沒(méi)有強(qiáng)制規(guī)定听隐,因此具體的虛擬機(jī)可以自由實(shí)現(xiàn)它补鼻。
-Navtive 方法是 Java 通過(guò) JNI 直接調(diào)用本地 C/C++ 庫(kù),可以認(rèn)為是 Native 方法相當(dāng)于 C/C++ 暴露給 Java 的一個(gè)接口,Java 通過(guò)調(diào)用這個(gè)接口從而調(diào)用到 C/C++ 方法风范。當(dāng)線程調(diào)用 Java 方法時(shí)咨跌,虛擬機(jī)會(huì)創(chuàng)建一個(gè)棧幀并壓入 Java 虛擬機(jī)棧。然而當(dāng)它調(diào)用的是 native 方法時(shí)硼婿,虛擬機(jī)會(huì)保持 Java 虛擬機(jī)棧不變锌半,也不會(huì)向 Java 虛擬機(jī)棧中壓入新的棧幀,虛擬機(jī)只是簡(jiǎn)單地動(dòng)態(tài)連接并直接調(diào)用指定的 native 方法寇漫。
參考資料:1.《深入淺出 Java 虛擬機(jī)》
2.http://www.reibang.com/p/8a775d747c47