深入JVM-虛擬機運行時內存
Java虛擬機的內存大致可以分成五個部分。詳見Java虛擬機運行時數據區
其中、方法區和Java堆是線程共享數據。而虛擬機棧、本地方法棧、程序計數器是線程專有的。
也就是說,每個線程都有自己的虛擬機棧、本地方法棧、程序計數器,并且共同使用一個方法區和Java堆
(圖片來源網絡)
線程私有區域
1. 程序計數器
首先要說的就是最簡單的程序計數器。
它是一個非常小的內存區域,用來存儲當前執行位置的行號。如果當前執行的是一個原生方法(Native).那么,這塊內存的值就是空的(Undefined)。
2. 虛擬機棧
虛擬機棧是Java方法執行的內存模型。
在方法執行之前,虛擬機會創建一個棧幀,用于存放局部變量表,操作數棧,動態鏈接,方法出口等信息。
需要分配多大的內存空間是完全確定的,在方法執行期間,空間大小不會改變。
兩種異常狀況:
線程請求的棧深度大于虛擬機所允許的深度。
在虛擬機可以動態拓展內存的情況下,擴展時無法申請到足夠的內存。
3. 本地方法棧
和虛擬機棧的作用相似,只不是本地方法棧是為本地方法(Native Method),而虛擬機棧是為Java方法服務。
在虛擬機規范中對本地方法棧中方法使用的語言、使用方式與數據結構并沒有強制規定,因此具體的虛擬機可以自由實現它。甚至有的虛擬機直接就把本地方法棧和虛擬機棧合二為一。與虛擬機棧一樣,本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。
共享區域內存
1. 堆內存
堆內存是Java虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區域,在虛擬機啟動時創建。此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存。這一點在Java虛擬機規范中的描述是:所有的對象實例以及數組都要在堆上分配。
注:是隨著JIT編譯器的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換、優化技術會導致一些微妙的變化發生,所有的對象都分配在堆上也變得不是那么絕對了
Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱做“GC堆”(Garbage Collected Heap)。從內存回收的角度來看,由于現在收集器基本都采用分代收集算法,所以Java堆中還可以細分為:新生代和老年代;再細致一點的有Eden空間、From Survivor空間、To Survivor空間等。從內存分配的角度來看,線程共享的Java堆中可能劃分出多個線程私有的分配緩沖區(Thread Local Allocation Buffer,TLAB)。不過無論如何劃分,都與存放內容無關,無論哪個區域,存儲的都仍然是對象實例,進一步劃分的目的是為了更好地回收內存,或者更快地分配內存。
Java堆可以處于物理上不連續的內存空間中,只要邏輯上是連續的即可,就像我們的磁盤空間一樣。在實現時,既可以實現成固定大小的,也可以是可擴展的,不過當前主流的虛擬機都是按照可擴展來實現的(通過-Xmx和-Xms控制)。如果在堆中沒有內存完成實例分配,并且堆也無法再擴展時,將會拋出OutOfMemoryError異常。
2. 方法區
方法區(Method Area)與Java堆一樣,是各個線程共享的內存區域,它用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。雖然Java虛擬機規范把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做Non-Heap(非堆),目的應該是與Java堆區分開來。
根據Java虛擬機規范的規定,當方法區無法滿足內存分配需求時,將拋出
OutOfMemoryError異常。
運行時常量池
運行時常量池(Runtime Constant Pool)是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法區的運行時常量池中存放。
Java JVM
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。