1. 程式人生 > >java虛擬機之內存模型

java虛擬機之內存模型

管理 char 責任 類信息 一個 最大 銷毀 虛擬機棧 接口

1. 概述

對於從事 C、C++ 程序開發的人員來說,在內存管理領域,他們既是擁有最高權力的「皇帝」又是從事基礎工作的「勞動人民」 --- 既擁有每個對象的「所有權」,又擔負著每一個對象生命開始到終結的維護責任。

但是對於 java 程序員來說,在虛擬機自動內存管理機制的幫助下,不需要再為每一個 new 操作寫配對的 delete/free 代碼,不容易出現在內存泄漏和內存溢出問題,由虛擬機管理內存這一切看起來都很美好。不過,也正是因為 java 程序員把內存控制的權利交給了 java 虛擬機,一旦出現內存泄漏和溢出方面的問題,如果不了解虛擬機是怎麽使用內存的,那麽排查錯誤將會成為一項非常艱難的工作。下面,我們了解一下 java 虛擬機的內存模型。

2. 運行時數據區域

在運行 java 程序中虛擬機會把內存劃分為不同的數據區域,這些區域有各自的用途以及創建和銷毀時間。按照規定,java 虛擬機包括以下幾個運行時內存區域。
技術分享圖片

2.1 程序計數器

程序計數器是一塊較小的內存空間,它可以看成是當前線程所執行字節碼的行號指示器。也就是說,在當前線程中,下一條需要執行的語句,比如分支、循環、跳轉、異常處理,是由它來引導的。

由於 java 支持多線程,為了保證線程切換之後還能夠順利運行,每個線程都會有一個獨立的程序計數器,各個線程之間的計數器互不影響,獨立存儲,我們稱這類內存區域為「線程私有」的內存。它是唯一一個在 java 虛擬機規範中沒有規定任何 OutOfMemoryError 情況的區域。

2.2 java虛擬機棧

與程序計數器一樣,java 虛擬機棧也是「線程私有」的,它描述的是 java 方法執行的內存模型:每個方法在執行的同時會創建一個 棧幀,用於存儲變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用到執行完成的過程,就對應著一個棧幀在虛擬機中入棧到出棧的過程。

局部變量表存放了編譯時可知的各種數據類型(boolean、byte、char、short、int、float、long、double)、對象引用和 returnAddress 類型。局部變量表所需要的內存空間在編譯期間完成分配,當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在運行期間不會改變。

對於這個區域,如果線程請求的棧深度大於虛擬機所允許的棧深度,將拋出 StackOverflowError 異常。大多數虛擬機都支持虛擬機棧的動態擴展,如果擴展無法申請到足夠的內存,就會拋出 OutOfMemoryError 異常。

2.3 本地方法棧

本地方法棧和虛擬機棧所發揮的作用非常相似,它們之間的區別不過是虛擬機棧為虛擬機執行 java 方法服務,而本地方法棧則為虛擬機使用 Native 方法服務。有的虛擬機甚至直接將本地方法棧和虛擬機棧合二為一。與虛擬機棧一樣,本地方法棧區域也會拋出 StackOverflowError 和 OutOfMemoryError 異常。

2.4 java堆

java 對(java Heap)是 java 虛擬機所管理的內存中最大的一塊,是被所有線程共享的一塊內存區域,在虛擬機啟動時創建,此內存區域的唯一目的就是存放對象

java 堆是垃圾收集器管理的主要區域,因此很多時候被稱為「GC堆」。java 堆內存還會有進一步的細分,這都是為了更好地回收內存,或者更快地分配內存。

根據 java 虛擬機規範的規定,java 堆可以是處於物理上不連續的內存空間,只要邏輯上是連續的即可,就像我們的磁盤空間一樣。當對中沒有內存完成實例分配時,並且堆也無法再擴展時,將會拋出 OutOfMemoryError 異常。

2.5 方法區

方法區和 java 堆一樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。java 虛擬機規範對方法區的限制非常寬松,其不需要連續的內存和可以選擇固定大小或者可擴展外,還可以選擇不實現垃圾收集,因為垃圾收集行為在這個區域出現的比較少,而且垃圾回收的「成績」也難以令人滿意。
註:在 JDK1.7 以後的版本中,已經把原本放在方法區的字符串常量池移除。

2.6 運行時常量池

運行時常量池是方法區的一部分。Class 文件中除了有各類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中。

運行時常量池相對於 Class 文件常量池的另外一個重要特征是具備動態性,java 語言並不要求常量一定只有編譯期才能產生,運行期間也可能將新的常量放入池中,這種特性被開發人員利用得比較多的是 String 類的 intern 方法。

以上就是 java 虛擬機的內存模型,主要內容摘自《深入理解 java 虛擬機》這本書。

java虛擬機之內存模型