JVM系列--03Java內存管理

Java內存區域簡介

在虛擬機自動內存管理機制的幫助下,不再需要像C++那樣爲每一個new操作去寫配對的delete/free代碼,不容易出現內存泄漏和內存溢出。

Java內存區域劃分

線程共享區

方法區(Method Area)
堆(Heap)

線程獨佔區

虛擬機棧(VM Stack)
本地方法棧(Native Method Stack)
程序計數器(Program Counter Register)

上圖
下圖綠色區塊由方法區、堆組成,是由所有線程共享的數據區(線程共享區)
紅色區塊由虛擬機棧、本地方法棧、程序計數器組成,線程隔離的數據區(線程獨佔區)
在這裏插入圖片描述

程序計數器

程序計數器是一塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器。
字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理線程恢復都需要依賴他
處於線程獨佔區,每個線程都有自己獨佔的程序計數器。
如果線程執行的是java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址。如果正在執 行的是native方法,這個計數器的值爲undefined。
此區域是唯一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域

虛擬機棧

虛擬機棧描述的是Java方法執行的動態內存模型
線程私有
棧幀(Stack Frame)
每個方法執行,都會創建一個棧幀,伴隨着方法從創建到執行完成。用於存儲局部變量表,操作數棧,動態鏈表,方法出口等。
局部變量表
存放編譯期可知的各種基本數據類型,引用類型,returnAddress類型。其中,64long、double佔用兩個Slot,其餘只佔用1個
局部變量表的內存空間在編譯期完成分配,當進入一個方法時,這個方法需要在幀分配多少內存是固定的,在方法運行期間是不會改變局部變量表的大小。
大小
棧內存溢出 :StackOverflowError
可動態擴展的虛擬機棧擴展時無法申請到足夠的內存:OutOfMemoryError

本地方法棧

本地方法棧與虛擬機棧非常類似,且HotSpot虛擬機是不區分兩者的。
爲虛擬機執行native方法服務
在虛擬機規範中對本地方法棧中方法使用的語言、使用方式與數據結構並沒有強制規定,因此具體的虛擬機可以自由實現它。
Hotspot直接將本地方法棧與虛擬機棧合二爲一

是Java虛擬機所管理的內存中最大的一塊,所有線程共享的一塊內存區域。
唯一目的是存放對象實例,幾乎所有的對象實例都在這裏分配內存。
隨着JIT編譯器的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化發生,所有對象都分配在堆上也就沒那麼絕對。
堆是垃圾收集器管理的主要區域,因此也被稱作“GC堆”。
由於現在收集器基本都採用分代收集算法,所以Java堆中還可以細分爲:新生代和老年代。
從內存分配的角度來看,線程共享的Java堆中可能劃分出多個線程私有的分配緩衝區。
如果在堆中 沒有內存 完成實例分配,並且堆也無法再擴展時,將會拋出OutOfMemoryError異常

方法區(Non-Heap)

存儲虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼等數據
類信息:
類的版本、字段、方法、接口
對於Hotspot,把GC分代收集擴展到了方法區中,所以很多人願意將方法區稱爲"永久代",兩者在JVM規範中並不等價
關於垃圾回收,方法區中會針對常量池的回收以及對象類型的卸載。
當申請內存區域失敗的情況下,同樣會拋出OutOfMemoryError異常。

運行時常量池

是方法區的一部分
用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。

直接內存

並不是Java虛擬機規範中定義的內存區域,但這部分內存也被頻繁地使用,而且也會導致OutOfMemoryError

發佈了15 篇原創文章 · 獲贊 6 · 訪問量 455
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章