jvm内存结构_浅谈JVM内存结构
JVM 可以分為 5 個部分,分別是:
類加載器(Class Loader):加載字節(jié)碼文件到內(nèi)存。
運行時數(shù)據(jù)區(qū)(Runtime Data Area):JVM 核心內(nèi)存空間結(jié)構(gòu)模型。
執(zhí)行引擎(Execution Engine):對 JVM 指令進行解析,翻譯成機器碼,解析完成后提交到操作系統(tǒng)中。
本地庫接口(Native Interface):供 Java 調(diào)用的融合了不同開發(fā)語言的原生庫。
本地方法庫(Native Libraies):Java 本地方法的具體實現(xiàn)。
JVM 的結(jié)構(gòu)如下圖所示:
這其中最復(fù)雜的是運行時數(shù)據(jù)區(qū),它也是 JVM 內(nèi)存結(jié)構(gòu)最重要的部分。運行時數(shù)據(jù)區(qū)又可以分為方法區(qū)、虛擬機棧、本地方法棧、堆以及程序計數(shù)器,并且方法區(qū)和堆是線程共享的,虛擬機棧、本地方法棧、程序計數(shù)器是線程隔離的。下面詳細(xì)講解運行時數(shù)據(jù)區(qū)的各個組成部分。
1.線程共享
方法區(qū):方法區(qū)與 Java 堆一樣,是各個線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。雖然 Java 虛擬機規(guī)范把方法區(qū)描述為堆的一個邏輯部分,但是它卻有一個別名叫做 Non-Heap(非堆),目的應(yīng)該是與 Java 堆區(qū)分開來。
堆:該區(qū)域是所有線程共享的,存放幾乎所有的對象實例。jvm管理的內(nèi)存中最大的一塊,也是GC收集器主要管理的區(qū)域。按回收內(nèi)存的角度可以分為新生代,老年代和永久代;再細(xì)分的話有Eden空間,From survior,To survior空間;不管如何劃分都是為了更好的回收內(nèi)存,存儲的也是對象實例。
新生代:新生代又可分為 Eden,from Survivor,to Survivor。Eden 區(qū)用來存放剛剛創(chuàng)建的對象,如果 Eden 區(qū)放不下,則放在 Survivor 區(qū),甚至老年代中。Survivor 區(qū)又可分為 Survivor From 和 Survivor To,GC 回收時使用,將 Eden 中存活的對象存入 Survior From 中,下一次回收時,將 Survior From 中的對象存入 Survior To 中,清除 Survior From ,下一次回收時重復(fù)此步驟,Survior From 變成 Survior To,Survivor To 變成 Survivor From,依次循環(huán),同時每次回收,對象的年齡都 +1,年齡增加到一定程度的對象,移動到老年代中。
老年代:存放年齡大的對象
永久代:jdk7之前就是用永久代來實現(xiàn)方法區(qū),本質(zhì)上來講兩者并不等價,僅因為Hotspot將GC分代擴展至方法區(qū),所以將其稱為永久代。在物理內(nèi)存上是和堆是連續(xù)的但邏輯上是隔離的;jdk8后移除了永久代,用元空間代替。使用的是本地內(nèi)存,這樣減少了內(nèi)存溢出的問題。
2.線程私有
本地方法棧:棧中方法都是用native修飾的,這些方法在Java中只有定義沒有具體實現(xiàn)。
- 由javah命令從.class文件轉(zhuǎn)換成.h文件(頭文件,里面包含函數(shù)原型和宏定義)
- 用.cpp文件實現(xiàn) .h 文件中的方法
- 將 .cpp 文件編譯成動態(tài)鏈接庫文件 .dll
- 使用 System.loadLibrary() 加載動態(tài)連接庫文件
調(diào)用native方法的基本原理是利用反射機制,在運行時找到 .dll 文件并且解析,根據(jù)動態(tài)鏈接庫中的文件名稱創(chuàng)建出對象和方法,然后就可以利用對象調(diào)用方法了。
虛擬機棧:實際上,Java 虛擬機棧是由一個個棧幀組成,而每個棧幀中都擁有:局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口信息。
局部變量表主要存放了編譯器可知的各種數(shù)據(jù)類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference 類型,它不同于對象本身,可能是一個指向?qū)ο笃鹗嫉刂返囊弥羔?#xff0c;也可能是指向一個代表對象的句柄或其他與此對象相關(guān)的位置)。
Java 虛擬機棧會出現(xiàn)兩種錯誤:StackOverFlowError 和 OutOfMemoryError。
- StackOverFlowError: 若 Java 虛擬機棧的內(nèi)存大小不允許動態(tài)擴展,那么當(dāng)線程請求棧的深度超過當(dāng)前 Java 虛擬機棧的最大深度的時候,就拋出 StackOverFlowError 錯誤。
- OutOfMemoryError: 若 Java 虛擬機棧的內(nèi)存大小允許動態(tài)擴展,且當(dāng)線程請求棧時內(nèi)存用完了,無法再動態(tài)擴展了,此時拋出 OutOfMemoryError 錯誤。
程序計數(shù)器:它是一塊較小的空間,可以看做當(dāng)前線程執(zhí)行字節(jié)碼的行號指示器。字節(jié)碼解釋器通過改變計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。 另外,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個獨立的程序計數(shù)器,各線程之間計數(shù)器互不影響,獨立存儲,我們稱這類內(nèi)存區(qū)域為“線程私有”的內(nèi)存。它也是jvm內(nèi)存里唯一一個不會出現(xiàn)OOM的區(qū)域。
總結(jié)
以上是生活随笔為你收集整理的jvm内存结构_浅谈JVM内存结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux多线程开发-线程同步-互斥锁p
- 下一篇: 图片完整检查linux,Linux 下的