jvm系列之記憶體區域
jvm系列之記憶體區域
1 執行時資料區域
想要了解jvm,那對其記憶體分配管理的學習是必不可少的;java虛擬機器在執行java程式的時候會把它所管理的記憶體劃分成若干資料區域。這些區域有著不同的功能、用途、建立/銷燬時間。java虛擬機器所分配管理的記憶體區域如圖1所示
1.1 程式計數器
程式計數器是一塊比較小的記憶體空間,它可以看做是當前執行緒所執行的位元組碼的執行位置的指標。在虛擬機器中位元組碼,直譯器工作時就是通過改變這個計數器的值來選取下一條需要執行的指令;虛擬機器完成分支、迴圈、跳轉、異常處理、執行緒恢復等功能都需要依靠它。
我們知道jvm多執行緒是通過執行緒的輪流切換並分配處理器執行時間的的方式來實現的,在任何時刻,一個處理器都只會執行一條執行緒中的指令。為了使執行緒被切換後能恢復到正確的執行位置,每條執行緒的程式計數器都應該是獨立的,各條執行緒之間的計數器互不干涉,獨立儲存————程式計數器的記憶體區域為執行緒私有的記憶體。
如果執行緒正在執行的是java方法,這個計數器記錄的是正在執行的虛擬機器位元組碼指令的地址;如果執行的是Native方法,這個計數器的值則為空。此記憶體區域是唯一一個在jvm規範中沒有規定任何OutOfMemoryerror情況的區域
1.2 java虛擬機器棧
java虛擬機器棧為執行緒私有的記憶體,其生命週期與執行緒相同。每個方法在執行的時候會建立一個棧幀用於儲存區域性變量表、運算元棧、方法出口等資訊。每一個方法從呼叫到執行完成,就對應著一個棧幀在虛擬機器中從入棧到出棧的過程。其區域性變量表存放了方法編譯期可知的各種基本資料型別、物件引用、returnAddress型別(指向一條位元組碼指令的地址)jvm規範中,這個區域規定了兩種異常狀況:StackOverflowError和OutOfMemoryError。
1.3 本地方法棧
本地方法棧的作用和虛擬機器棧的作用很相似,它們的區別在於虛擬機器棧為虛擬機器執行java方法服務,而本地方法棧則為執行本地方法服務。有的虛擬機器直接把本地方法棧和虛擬機器棧二合一。與虛擬機器棧一樣,本地方法棧的異常也有兩個:StackOverflowError和OutOfMemoryError。
1.4 java堆區
java堆是虛擬機器所管理的記憶體中最大的一塊,它是被所有執行緒共享的一塊記憶體區域,該區域在虛擬機器啟動的時候建立。這個區域的唯一目的就是存放物件例項。java堆是垃圾收集器工作的主要區域,由於垃圾收集器基本都採用分代收集的演算法,所以java堆從垃圾收集器的角度來劃分可以細分為新生代和老年代;從記憶體分配的角度來看,執行緒共享的java堆可能劃分出多個執行緒私有的分配緩衝區。
java堆區可以是物理上不連續的記憶體空間,只要邏輯上是連續的即可;一般而言我們的虛擬機器java堆記憶體不是固定大小的,是可以擴充套件的。如果在堆中沒有足夠記憶體分配給物件例項,並且堆記憶體無法再擴充套件時,虛擬機器將會丟擲OutOfMemoryError異常。
1.5 方法區
方法區與java堆區一樣是各個執行緒共享的記憶體區域,這個區域儲存了類資訊、常量、靜態變數等資料。java虛擬機器規範中把方法區描述為堆得一部分邏輯,它又有一個名字——非堆,目的是與普通java堆進行區分。相對而言垃圾收集器在這個區域很少活動,因此一部分人把這個區域叫做“永久代”。這個區域的記憶體回收目標主要是針對常量池的回收和型別的解除安裝,然而型別解除安裝的條件是很苛刻的。該區域和和java堆區一樣,當記憶體不夠分配時會丟擲OutOfMemoryError.
1.6 執行時常量池
執行時常量池是方法區的一部分;一個Class檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是編譯時常量池,用於存放編譯期生成的常量。編譯時常量池在類被載入後會放入方法區的執行時常量池中。與編譯期常量池不同的是,運執行時常量池是動態的,執行期間產生的新的常量也會被放入這個區域,如:String類的intern()方法。
小結
該篇對jvm記憶體只能算一個概覽,給小夥伴們介紹了一些概念性的東西,很多地方是值得去深入研究的,比如具體一個物件例項是如何被分配到堆記憶體的,類的載入過程,方法執行時方法棧的入棧與出棧的具體過程······。jvm博大精深,我在這提供一個梗概,小夥伴們如果有時間可以細細推敲推敲。