運行時數據區由 程序計數器、java虛擬機棧、本地方法棧、堆、方法區 組成;java
每個Java線程都有一個程序計數器,用於保存程序執行到當前方法的哪個指令,它是線程私有的。函數
此內存區域是惟一一個在VM Spec中沒有規定任何OutOfMemoryError狀況的區域。spa
一般說的棧指的就是Java棧,主管Java程序的運行。棧是在線程建立時建立,線程結束棧內存就釋放掉了,不存在垃圾回收問題,線程一結束該棧就Over,與程序計數器同樣,它的生命週期也是與線程相同,它是線程私有的。線程
基本類型的變量、實例方法、引用類型變量都是在函數的棧內存中分配。3d
棧描述的是Java方法調用的內存模型:每一個方法被執行的時候,都會同時建立一個幀(Frame)用於存儲本地變量表、操做棧、動態連接、方法出入口等信息。每個方法的調用至完成,就意味着一個幀在VM棧中的入棧至出棧的過程。本地變量表存放了編譯期可知的各類標量類型(boolean、byte、char、short、int、float、long、double)、對象引用(不是對象自己,僅僅是一個引用指針)、方法返回地址等指針
這個區域規定了2種異常:若是線程請求的棧深度大於虛擬機所容許的深度,將拋出StackOverflowError異常;若是VM棧能夠動態擴展(VM Spec中容許固定長度的VM棧),當擴展時沒法申請到足夠內存則拋出OutOfMemoryError異常。code
(1)拋出StackOverflowError異常的代碼(遞歸調用):對象
public class StackDemo1 { static void sayHello() { System.out.println("AAAAA"); sayHello(); } public static void main(String[] args) { sayHello(); } }
本地方法棧和Java虛擬機棧發揮的做用是相似的,只不過Java虛擬機棧爲虛擬機運行原語服務,而本地方法棧是爲虛擬機使用到的 native 服務。blog
它的實現語言、結構、方式沒有強制規定,甚至有的虛擬機把它和java虛擬機棧合二爲一了,例如Sun Hotspot。遞歸
和java虛擬機棧同樣,這個區域也會拋出StackOverflowError異常和OutOfMemoryError異常。
Java7以前:
一個JVM實例只存在於一個堆內存中,堆內存的大小是能夠調節的。類加載器讀取了類文件以後,須要把類、方法、常變量放到堆內存中,
保存全部引用類型的真實信息,以方便執行器執行。
堆內存邏輯上分爲:新生區、養老區、永久區。(實際上永久區被稱爲非堆內存)
新生區:伊甸區(Eden Space)、倖存0區(Survivor 0 Space)、倖存1區(Survivor 1 Space)
當new 一個對象,該對象被放入伊甸區(Eden),建立的對象愈來愈多,伊甸區(Eden)快滿的時候啓動一種輕垃圾回收(Minor GC),未被回收的對象被放入倖存0區(Survivor 0),Eden被清空;當倖存0區快滿了,未被回收的對象被放入倖存1區(Survivor 1),Survivor 0和Eden被清空;Survisor 0與Survivor 1交換角色,如此循環往復。若是對象的複製次數達到16次,該對象就會被送到養老中。當養老區快滿的時候觸發一個重量級的GC(Major GC),清理以後仍是沒法再保存對象,就會產生OOM異常(OutOfMemoryError)。
Survisor 0 和 Survivor 1會一直調換角色,誰是空的誰就是Survivor 1區。
方法區是全部線程共享的,一般用來儲存裝載的類的元結構信息。垃圾回收不多發生;
好比:運行時常量池 + 靜態變量 + 常量 + 字段 + 方法字節碼 + 在類/實例/接口初始化用到的特殊方法等。
一般和永久區關聯在一塊兒(Java7),具體的跟JVM的實現和版本有關。Java8之後,變爲了MetaSpace(元空間),直接使用的物理內存,垃圾回收運行的機率變得更低。