1. 程式人生 > >jvm記憶體模型和記憶體分配

jvm記憶體模型和記憶體分配

http://www.w2bc.com/Article/83700

1.什麼是jvm?
(1)jvm是一種用於計算裝置的規範,它是一個虛構出來的機器,是通過在實際的計算機上模擬模擬各種功能實現的。
(2)jvm包含一套位元組碼指令集,一組暫存器,一個棧,一個垃圾回收堆和一個儲存方法域。
(3)JVM遮蔽了與具體作業系統平臺相關的資訊,使Java程式只需生成在Java虛擬機器上執行的目的碼(位元組碼),就可以在多種平臺上不加修改地執行。
JVM在執行位元組碼時,實際上最終還是把位元組碼解釋成具體平臺上的機器指令執行。

2.jdk、jre、jvm是什麼關係?
(1)JRE(Java Runtime Environment),也就是java平臺。所有的java程式都要在JRE環境下才能執行。
(2)JDK(Java Development Kit),是開發者用來編譯、除錯程式用的開發包。JDK也是JAVA程式需要在JRE上執行。
(3)JVM(Java Virtual Machine),是JRE的一部分。它是一個虛構出來的計算機,是通過在實際的計算機上模擬模擬各種計算機功能來實現的。
JVM有自己完善的硬體架構,如處理器、堆疊、暫存器等,還具有相應的指令系統。
Java語言最重要的特點就是跨平臺執行。使用JVM就是為了支援與作業系統無關,實現跨平臺。

3.JVM原理
(1)jvm是java的核心和基礎,在java編譯器和os平臺之間的虛擬處理器,可在上面執行位元組碼程式。
(2)java編譯器只要面向jvm,生成jvm能理解的位元組碼檔案。java原始檔經編譯成位元組碼程式,通過jvm將每條指令翻譯成不同的機器碼
,通過特定平臺執行。

4. JVM執行程式的過程
1) 載入.class檔案 
2) 管理並分配記憶體 
3) 執行垃圾收集
JRE(java執行時環境)由JVM構造的java程式的執行環,也是Java程式執行的環境,但是他同時一個作業系統的一個應用程式一個程序,
因此他也有他自己的執行的生命週期,也有自己的程式碼和資料空間。
JVM在整個jdk中處於最底層,負責於作業系統的互動,用來遮蔽作業系統環境,
提供一個完整的Java執行環境,因此也就虛擬計算機。

作業系統裝入JVM是通過jdk中Java.exe來完成,
通過下面4步來完成JVM環境:
1) 建立JVM裝載環境和配置 
2) 裝載JVM.dll 
3) 初始化JVM.dll並掛界到JNIENV(JNI呼叫介面)例項
4) 呼叫JNIEnv例項裝載並處理class類。

5. JVM的生命週期


1) JVM例項對應了一個獨立執行的java程式它是程序級別 
a) 啟動。啟動一個Java程式時,一個JVM例項就產生了,任何一個擁有public static void 
main(String[] args)函式的class都可以作為JVM例項執行的起點 
b) 執行。main()作為該程式初始執行緒的起點,任何其他執行緒均由該執行緒啟動。JVM內部有兩種執行緒:守護執行緒和非守護執行緒,main()屬於非守護執行緒,守護執行緒通常由JVM自己使用,java程式也可以表明自己建立的執行緒是守護執行緒 
c) 消亡。當程式中的所有非守護執行緒都終止時,JVM才退出;若安全管理器允許,程式也可以使用Runtime類或者System.exit()來退出 
2) JVM執行引擎例項則對應了屬於使用者執行程式的執行緒它是執行緒級別的

 6、JVM記憶體模型

(1)java程式碼具體執行過程如下圖,

(2)執行時資料區,即jvm記憶體結構圖如下圖

(3)執行時資料區儲存了哪些資料?

  a) 程式計數器(PC暫存器)

      由於在JVM中,多執行緒是通過執行緒輪流切換來獲得CPU執行時間的,因此,在任一具體時刻,一個CPU的核心只會執行一條執行緒中的指令,

  因此,為了能夠使得每個執行緒都線上程切換後能夠恢復在切 換 之前的程式執行位置,每個執行緒都需要有自己獨立的程式計數器,並且不能互相被幹擾,

  否則就會影響到程式的正常執行次序。因此,可以這麼說,程式計數器是每個執行緒所私有的。由於程式計數器中儲存的資料所佔空間的大小不會隨程式的執行而發生改變,

  因此,對於程式計數器是不會發生記憶體溢位現象(OutOfMemory)的。

  b) java棧

      Java棧中存放的是一個個的棧幀,每個棧幀對應一個被呼叫的方法,在棧幀中包括區域性變量表(Local Variables)運算元棧(Operand Stack)

    指向當前方法所屬的類的執行時常量池(執行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、

    方法返回地址(Return Address)和一些額外的附加資訊。當執行緒執行一個方法時,就會隨之建立一個對應的棧幀,並將建立的棧幀壓棧。當方法執行完畢之後,便會將棧幀出棧。 

  c)本地方法棧

  本地方法棧與Java棧的作用和原理非常相似。區別只不過是Java棧是為執行Java方法服務的,而本地方法棧則是為執行本地方法(Native Method)服務的

  d)堆

  Java中的堆是用來儲存物件本身的以及陣列(陣列引用是存放在Java棧中的)。堆是被所有執行緒共享的,在JVM中只有一個堆。

  e)方法區

  與堆一樣,是被執行緒共享的區域。在方法區中,儲存了每個類的資訊(包括類的名稱、方法資訊、欄位資訊)、靜態變數、常量以及編譯器編譯後的程式碼等。

  在Class檔案中除了類的欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用來儲存編譯期間生成的字面量和符號引用。

  在方法區中有一個非常重要的部分就是執行時常量池,它是每一個類或介面的常量池的執行時表示形式,在類和介面被載入到JVM後,

  對應的執行時常量池就被創建出來。當然並非Class檔案常量池中的內容才能進入執行時常量池,在執行期間也可將新的常量放入執行時常量池中,比如String的intern方法。

  7、JVM記憶體溢位的情況

  

  a) 程式計數器(Program Counter Register)

  每條執行緒都有一個獨立的的程式計數器,各執行緒間的計數器互不影響,因此該區域是執行緒私有的。該記憶體區域是唯一一個在Java虛擬機器規範中沒有規定任何OOM(記憶體溢位:OutOfMemoryError)情況的區域。

  b)Java虛擬機器棧(Java Virtual Machine Stacks)

    在Java虛擬機器規範中,對這個區域規定了兩種異常情況:

      1、如果執行緒請求的棧深度大於虛擬機器所允許的深度,將丟擲StackOverflowError異常。

      2、如果虛擬機器在動態擴充套件棧時無法申請到足夠的記憶體空間,則丟擲OutOfMemoryError異常。

           這兩種情況存在著一些互相重疊的地方:當棧空間無法繼續分配時,到底是記憶體太小,還是已使用的棧空間太大,其本質上只是對同一件事情的兩種描述而已。

       在單執行緒的操作中,無論是由於棧幀太大,還是虛擬機器棧空間太小,當棧空間無法分配時,虛擬機器丟擲的都是StackOverflowError異常,而不會得到OutOfMemoryError異常。

           而在多執行緒環境下,則會丟擲OutOfMemoryError異常。

  c)堆Java Heap

    Java Heap是Java虛擬機器所管理的記憶體中最大的一塊,它是所有執行緒共享的一塊記憶體區域。幾乎所有的物件例項和陣列都在這類分配記憶體。Java Heap是垃圾收集器管理的主要區域,因此很多時候也被稱為“GC堆”。

      根據Java虛擬機器規範的規定,Java堆可以處在物理上不連續的記憶體空間中,只要邏輯上是連續的即可。如果在堆中沒有記憶體可分配時,並且堆也無法擴充套件時,將會丟擲OutOfMemoryError異常。   

  d)方法區域,又被稱為“永久代”,當方法區無法滿足記憶體分配需求時,將丟擲OutOfMemoryError異常。

  參考資料:http://www.cnblogs.com/dolphin0520/p/3613043.html

  參考資料:http://www.cnblogs.com/sunada2005/p/3577799.html

  參考資料:http://blog.csdn.net/ns_code/article/details/17565503