?前言:
? ? ? ? java虛擬機(jī)再執(zhí)行Java程序的時(shí)候把它所擁有的內(nèi)存區(qū)域劃分了若干個(gè)數(shù)據(jù)區(qū)域。這些區(qū)域有著不同的功能,各司其職。這些區(qū)域不但功能不同,創(chuàng)建、銷毀時(shí)間也不同。有些區(qū)域?yàn)榫€程私有,如:每個(gè)線程都有自己的程序計(jì)數(shù)器,則程序計(jì)數(shù)器隨著用戶線程創(chuàng)建而創(chuàng)建,隨其銷毀而銷毀。而有些區(qū)域是所有線程共有的,如堆是被所有線程所共有的。根據(jù)《java虛擬機(jī)規(guī)范》的規(guī)定,java虛擬機(jī)所管理的內(nèi)存將會(huì)包括以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域:
?注意:JVM可以說是一套規(guī)范。
下面我來分別詳細(xì)介紹這五個(gè)區(qū)域。?
1.程序計(jì)數(shù)器(線程隔離)
? ? ? ? 程序計(jì)數(shù)器是一塊較小的內(nèi)存空間。它的作用是記錄這個(gè)線程下一個(gè)指令的位置。Java虛擬機(jī)的多線程是通過線程輪流切換、分配處理器執(zhí)行時(shí)間的方式來實(shí)現(xiàn)的。在多線程當(dāng)中,線程在執(zhí)行完自己所被分配到的時(shí)間片后會(huì)被切換線程,我們無(wú)法保證線程執(zhí)行完畢后再被切換(時(shí)間片的大小是不確定的)。為了保證線程切換回來后能恢復(fù)到正確的執(zhí)行位置。所以我們需要程序計(jì)數(shù)器為我們記錄下一條指令的地址,等線程重新?lián)尰谻PU時(shí),去這個(gè)程序計(jì)數(shù)器當(dāng)中取到下一條指令的地址,繼續(xù)往下執(zhí)行,這就是程序計(jì)數(shù)器的主要作用。所以每個(gè)線程都需要自己的程序計(jì)數(shù)器,互不影響。所以程序計(jì)數(shù)器是線程私有的。
????????總結(jié)來說:它是程序控制流的指示器,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)程序計(jì)數(shù)器來完成。
2.java虛擬機(jī)棧(線程隔離)
? ? ? ? 虛擬機(jī)棧和程序計(jì)數(shù)器一樣都是線程私有的,生命周期與其對(duì)應(yīng)的線程相同。這個(gè)虛擬機(jī)棧內(nèi)部保存一個(gè)個(gè)的棧幀(Stack Frame),用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法返回等信息。每一個(gè)方法從開始執(zhí)行到執(zhí)完畢都代表著一個(gè)棧幀再虛擬機(jī)棧中入棧到出棧。它于虛擬機(jī)執(zhí)行時(shí)方法調(diào)用和方法執(zhí)行時(shí)的數(shù)據(jù)結(jié)構(gòu),它是虛擬棧的基本元素。
????????在棧幀中的局部變量表中存放著基本數(shù)據(jù)類型數(shù)據(jù)和對(duì)像引用。這個(gè)基本類型是確確實(shí)實(shí)的存儲(chǔ)再棧幀中,而對(duì)象引用在這里存的不是真正意義上的對(duì)象,可能是一個(gè)指向?qū)ο笃鹗嫉刂返囊弥羔?,也可能是指向?qū)ο蟮哪莻€(gè)句柄或者其他與此對(duì)象相關(guān)的位置。
? ? ? ? 這些數(shù)據(jù)在局部變量表中存儲(chǔ)空間大小以局部變量槽(Slot)來表示。除了double、long類型的數(shù)據(jù)占兩個(gè)變量槽之外,其余數(shù)據(jù)類型占的是一個(gè)變量槽。所以說這個(gè)方法需要多大的局部變量空間在剛調(diào)用這個(gè)方法就已經(jīng)確定了。在方法運(yùn)行期間不會(huì)改變局部變量表的大小。
在這個(gè)數(shù)據(jù)區(qū)域規(guī)定了兩種異常情況:
- StackOverflowError異常:當(dāng)線程申請(qǐng)線程深度大于Java虛擬機(jī)所允許的深度,就會(huì)報(bào)這個(gè)異常。
- OutOfMemoryError異常:當(dāng)虛擬機(jī)??梢詣?dòng)態(tài)擴(kuò)展的時(shí)候無(wú)法申請(qǐng)到足夠大的深度時(shí)就會(huì)報(bào)這個(gè)異常。
3.本地方法棧(線程隔離)
????????這個(gè)區(qū)域和虛擬機(jī)棧差不多。兩者不同的是虛擬機(jī)棧為虛擬機(jī)執(zhí)行的是java(也就是字節(jié)碼)方法,而本地方法棧為虛擬機(jī)執(zhí)行的是用于執(zhí)行本地(非Java)方法。甚至有一些虛擬機(jī)將虛擬機(jī)棧和本地方法棧合二為一。與虛擬機(jī)棧一樣,本地方法棧也會(huì)在棧深度溢出或者棧擴(kuò)展失 敗時(shí)分別拋出StackOverflowError和OutOfMemoryError異常。
4.java堆(線程共享)
????????堆是JVM中最大的一塊內(nèi)存區(qū)域。堆是所有線程共享的區(qū)域,在堆中,對(duì)象的創(chuàng)建和銷毀都是由垃圾回收器自動(dòng)管理的。它在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,Java 世界里“幾乎”所有的對(duì)象實(shí)例都在這里分配內(nèi)存。但還是有些情況下不是在堆上的。
-
方法內(nèi)聯(lián)優(yōu)化:在某些情況下,編譯器會(huì)進(jìn)行方法內(nèi)聯(lián)優(yōu)化,將方法的調(diào)用直接替換為方法體內(nèi)的代碼。這種優(yōu)化可以使得對(duì)象實(shí)例的創(chuàng)建在棧上進(jìn)行,而不是在堆上。這種情況下,對(duì)象實(shí)例的生命周期可能會(huì)比較短暫。
-
線程私有對(duì)象:有些對(duì)象只被某個(gè)線程所擁有,并且不會(huì)被其他線程訪問。這樣的對(duì)象可以在棧上分配,從而實(shí)現(xiàn)更高效的內(nèi)存訪問。
????????Java堆既可以被實(shí)現(xiàn)成固定大小的,也可以是可擴(kuò)展的,不過當(dāng)前主流的Java虛擬機(jī)都是按照可擴(kuò) 展來實(shí)現(xiàn)的如果在Java堆中沒有內(nèi)存完成實(shí)例分配,并且堆也無(wú)法再 擴(kuò)展時(shí),Java虛擬機(jī)將會(huì)拋出OutOfMemoryError異常。
5.方法區(qū)(線程共享)
其實(shí)方法區(qū)是在JDK1.8以前的版本里存在的一塊內(nèi)存區(qū)域,主要就是存放從class文件里加載進(jìn)來的類的,而且常量池也是在這塊區(qū)域內(nèi)的。
但是在JDK1.8之后,這塊區(qū)域搖身一變,換了名字,叫做“Metaspace”,翻譯過來就是“元數(shù)據(jù)空間”的意思,當(dāng)然它只是改了個(gè)名,實(shí)現(xiàn)的功能是沒變的。
方法區(qū)(Method Area)與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類型信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存等數(shù)據(jù)。
5.1 類型信息
對(duì)每個(gè)加載的類型(類class、接口interface、枚舉enum、注解annotation),JVM必須在方法區(qū)中存儲(chǔ)以下類型信息:
①這個(gè)類型的完整有效名稱(全名=包名.類名)
②這個(gè)類型直接父類的完整有效名(對(duì)于interface或是java.lang.0bject,都沒有父類)
③這個(gè)類型的修飾符(public, abstract,final的某個(gè)子集)
④這個(gè)類型直接接口的一個(gè)有序列表
5.2域信息(Field)成員變量
JVM必須在方法區(qū)中保存類型的所有域的相關(guān)信息以及域的聲明順序。
域的相關(guān)信息包括:域名稱、域類型、域修飾符(public, private,protected,static,final, volatile, transient的某個(gè)子集)文章來源:http://www.zghlxwxcb.cn/news/detail-648874.html
5.3方法(Method)信息
JVM必須保存所有方法的以下信息,同域信息一樣包括聲明順序:文章來源地址http://www.zghlxwxcb.cn/news/detail-648874.html
- 方法名稱
- 方法的返回類型(或void)·方法參數(shù)的數(shù)量和類型(按順序)
- 方法的修飾符(public, private,protected,static, final,synchronized,native,abstract的一個(gè)子集)
- 方法的字節(jié)碼(bytecodes)、操作數(shù)棧、局部變量表及大小(abstract和native方法除外)
到了這里,關(guān)于JVM運(yùn)行時(shí)五大數(shù)據(jù)區(qū)域詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!