Java虛擬機在執行Java程序的過程中會把它所管理的內存劃分爲若干個不同的數據區,這些區域都有各自的用途。創建和銷燬的時間,有的區域隨着虛擬機進程的啓動而存在,有些區域則依賴用戶線程的啓動和結束而建立和銷燬。
Java虛擬機所管理的內存將會包括以下幾個運行時數據區域:
1、程序計數器
2、Java虛擬機棧
3、本地方法棧
4、Java堆
5、方法區
6、運行時常量池
下面分別介紹各個內存分區及它們的作用:
1、程序計數器
程序計數器是一塊很小的內存分區,你可以把它看做當前線程所執行的字節碼的指示器。
在虛擬機的概念模型裏,字節碼解釋器工作時,就是通過改變計數器的值來選擇下一條需要執行的字節碼指令。
程序技術器爲線程私有,每個線程都有它們各自的程序計數器,這樣再多線程的情況下,線程之間的來回切換,也能正確找到上次切換時執行的位置。
如果線程正在執行的是一個Java方法,那麼程序計數器記錄的是當前線程正在執行的字節碼指令的地址;如果線程正在執行的是一個native方法,則計數器值爲空。
此內存區域是唯一一個Java虛擬機規範中沒有規定任何OutOfMemoryError(OOM)情況的區域。
2、Java虛擬機棧
虛擬機棧也爲線程私有的,它的生命週期與線程相同;
虛擬機棧可以看做是Java方法執行的內存模型:每個方法執行的同時都會創建一個棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。一個Java方法從調用到執行完的過程,就對應着一個棧幀從虛擬機棧入棧到出棧的過程;
局部變量表中存放了編譯期可知的基本數據類型、對象引用、returnAddress類型(指向了一條字節碼指令的地址);
在虛擬機棧中可能會出現兩種異常:StackOverflowError和OutOfMemory
StackOverflowError:如果線程請求的棧深度大於當前虛擬機所允許的深度,會拋出該異常;
OutOfMemory:如果虛擬機棧可以動態擴展,當擴展時無法申請到足夠的內存,會拋出該異常;
3、本地方法棧
本地方法棧類似與虛擬機棧,它們不同之處在於,虛擬機棧是爲虛擬機執行的Java方法服務,而本地方法棧是爲虛擬機使用到的Native方法服務;
在HotSpot虛擬機中直接把本地方法棧和虛擬機棧合二爲一;
在本地方法棧可能會出現兩種異常:StackOverflowError和OutOfMemory
4、Java堆
Java堆是被所有線程共享的一塊區域,它也是Java虛擬機管理的內存中最大的一塊,它在虛擬機啓動時創建;
Java堆唯一的目的就是存放對象實例,幾乎所有的對象實例的都在這裏分配內存;
Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱爲GC堆;
Java堆可以處於物理上不連續的內存空間中,只要邏輯上連續即可,在實現時既可以是固定大小也可以是可擴展的,如果堆中沒有內存完成實例分配,並且堆也無法再擴展時,將會拋出OutOfMemory異常;
5、方法區
方法區也是內存共享的一塊區域,它用於存放已被虛擬機加載的類信息、常量、靜態變量、即使編譯器編譯後的代碼等數據;
在HotSpot虛擬機中,通常把方法區稱之爲永久代,本質上兩者並不相同,只是HotSpot虛擬機的設計團隊使用永久代來實現方法區;
方法區中,垃圾收集比較少見,但並不是不進行GC,這個區域的回收目標主要是針對常量池的回收和對類型的卸載
方法區類似於Java堆,不要連續的內存和可以選擇固定大小或者可擴展。它還可以選擇不實現垃圾收集;
當方法區無法滿足內存分配需求時,會拋出OutOfMemory異常;
6、運行時常量池
運行時常量池,是方法區的一部分,常量池用於存放編譯期生成的各種字面量和符號引用,它具有動態性,不要求常量一定只有編譯期才能產生,運行期間也可能將新的常量放入池中;(例:String.intern()方法)
參考:《深入理解Java虛擬機》