一、程序計數器(Program Counter Register)
- 一塊較小的內存空間,可看做是當前線程所執行的字節碼的行號指示器。
- 在java多線程中,每條線程都有一個獨立的程序計數器,各條線程之間的計數器互不影響,獨立存儲。(線程私有的內存)
- 如果線程執行的是java方法,則程序計數器記錄的是正在執行的虛擬機字節碼指令的地址;如果線程執行的是Native方法,這個計數器值則爲空。
- 該內存區域是java虛擬機規範中唯一沒有規定OutOfMemoryError情況的區域。
二、虛擬機棧(VM Stack)
- 描述Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(用於存儲局部變量表、操作樹棧、動態鏈接、方法出口等信息)
- 每一個方法被調用直至執行完成,就對應着一個棧幀在虛擬機中從入棧到出棧的過程。
- 局部變量表:基本數據類型、對象引用(可能是指向對象起始地址的引用指針、可能是指向一個代表對象的句柄或者其他與此對象相關的位置)和returnAddress類型(指向了一條字節碼指令的地址);該表所需的內存空間在編譯期間完成分配,在運行期間不改變。
- 64位的long和double類型會佔用2個局部變量空間(Slot),其餘基本數據類型佔用1個。
- 該區域引起的兩個異常:一是如果線程請求的棧深度大於虛擬機所允許的深度,將跑出StackOverflowError異常;一是如果虛擬機棧可以動態擴展,當擴展時無法申請到足夠的內存時會拋出OutOfMemoryError異常
三、本地方法棧(Native Method Stacks)
- 同虛擬機棧類似,當本地方法棧是爲虛擬機使用到的Native方法服務。
- 有些虛擬機(如 Sun HotSpot虛擬機)直接將本地方法棧和虛擬機棧合二爲一。
- 同樣會拋出StackOverflowError和OutOfMemoryError異常。
四、堆(Heap,GC Heap)
- 被所有線程所共享,在虛擬機啓動時就被創建。
- 唯一目的:存放對象實例,幾乎所有的對象實例和數組都在堆上分配(現在不絕對,因爲JIT編譯器的發展和逃逸分析技術的成熟)。
- 可能劃分出多個線程私有的分配緩衝區(Thread Local Allocation Buffer,TLAB).
- 可處在物理上不連續的內存空間中,只要邏輯上是連續的就行。
- 堆無法再擴展時,跑出OutOfMemoryError異常。
五、方法區(Method Area)
- 被所有線程所共享,在虛擬機啓動時被創建。
- 用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。
- 有時候被稱爲“永久代”。
- 當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。
六、運行時常量池(Runtime Constant Pool)
- 方法區的一部分。
- Class文件中有類的版本、字段、方法、接口、常量池等信息,其中常量池用於存儲編譯器後生成的各種字面量和符號引用,這部分內容將在類載入後存放到運行時常量池。
- 可在運行時將新的常量加入常量池中,如String的intern()方法。
- 當常量池無法再申請到內存時會拋出OutOfMemoryError異常。
七、直接內存(Direct Memory)
- 並不是虛擬機運行時數據區的一部分,也不是java虛擬機規範中定義的內存區域,但是這部分內存也被頻繁使用。
- JDK1.4中加入的NIO類,引入一種基於通道(Channel)與緩衝區的I/O方式,它可以使用Native函數庫直接分配堆外內存,然後通過一個存儲在java堆裏面的DirectByteBuffer對象作爲這塊內存的引用進行操作。