天天看點

JVM運作時記憶體區域劃分

JVM運作時的記憶體區域分為:程式計數器,虛拟機棧,本地方法棧,堆,方法區,運作時常量池以及直接記憶體區域

線面主要來分别說下這些區域的存儲内容作用

1.程式計數器

   程式計數器是線程私有的,目前線程所執行的位元組碼行号訓示器。位元組碼解析器通過改變這個計數器來選取下一條需要執行的位元組碼指令。

  執行java方法的時候,儲存的是正在執行的虛拟機位元組碼指令位址,執行本地方法的時候儲存的是空

  在jvm記憶體模型中唯一一個沒有OOM異常的區域

2.虛拟機棧

  也是線程私有的,生命周期與線程相同。此塊區域描述的是方法執行的記憶體模型。每一個方法從調用到執行完成在虛拟機棧中描述的都是棧幀的入棧和出棧,虛拟機棧中的儲存的是局部常量表,操作數棧,動态連結和方法出口等

  很多時候,我們在描述jvm記憶體的時候,喜歡說棧和堆,這樣的描述是很粗糙的,而這裡的棧就是指我們的虛拟機棧

  虛拟機棧中會抛出stackOverFlowError異常和OOM異常。線程請求的棧的深度大于虛拟機允許的棧的深度的時候,會抛出SOF異常。同樣的;當擴充的時候無法申請到足夠的記憶體的時候,會抛出OutOfMemoryError異常

  注意兩個知識點:局部變量表中儲存有基本資料類型,對象引用和returnAddress類型;long和double占用2個局部變量空間,其他的占用一個局部變量空間

3.本地方法棧

  本地方法棧與虛拟機棧類似。差别在于,本地方法棧為虛拟機的本地方法服務。在jvm規範中,本地方法棧中的方法實作和資料類型沒有做嚴格的規定,是以本地方法棧可以自由的實作,包括不使用java語言。在Hotspot中,本地方法棧被合并到了虛拟機棧中。本地方法棧也會抛出StackOverFlowError異常和OutOfMemoryError異常

4.java堆

  java堆是jvm中最大的一塊區域,此區域是共享的,在虛拟機初始化的時候建立的。java堆中儲存着具體的java對象執行個體,幾乎所有的對象執行個體都儲存在這個區域中。java虛拟機規範中規定,所有的數組和對象執行個體都儲存在java堆中,但是随着JIT編譯器的發展和逃逸分析技術的逐漸成熟,這個也成了并非絕對的。

  jvm規範中,java堆在實體記憶體上并不一定要是連續的,隻要保證在邏輯上是連續的即可

  java堆的大小可以通過-Xmx和-Xmn來設定最大最小值,當然也可以設定成固定大小的

  在這個區域中,當沒有足夠記憶體配置設定對象的時候(GC之後),則會抛出OutOfMemoryError異常

5.方法區

  方法區與java堆一樣,是線程共享的區域,此區域中儲存着類資訊,變量,靜态變量,即時編譯器編譯後的代碼等資料。在java虛拟機規範中,也将方法區描述為java堆的一部分,但是方法區還有另一個名字叫Non-Heap,目的也是為了與java堆區分開

  hotSpot上,習慣将這個區域叫永久帶,因為hotspot團隊将GC分代收集擴充到這個區域,或者是使用永久帶來實作了方法區,但是本質上這兩者是不能對等的

  java虛拟機規範對于方法區的限制也是很寬松的,如存儲的不需要實體上連續的,隻要邏輯上連續即可,與java堆一樣。

  這個區域的GC是很少的,因為要回收的内容要求太苛刻,造成回收的效率不高,但是并不意味着就不進行GC,隻是回收的成績不夠滿意

   此區域也會出現OutOfMemoryError異常

6.運作時常量池

  運作時常量池是方法區的一部分,儲存着編譯期生成的各種字面量和符号引用

  運作時常量池相對于class檔案常量池,多了動态性。java并不要求常量隻有在編譯器産生,運作期間也有可能将常量寫入運作時常量池中,如String的intern方法

  此區域與方法區一樣,會跑村OutOfMemoryError

7.直接記憶體

  直接記憶體并不是虛拟機運作時資料區域的一部分,也不是java虛拟機規範中的記憶體區域  自jdk1.4之後,加入了NIO,引入

了一種基于通道與緩存區的I/O方式,可以使用直接記憶體,提高了效率,因為使用直接記憶體便不用将對象從直接記憶體拷貝到堆中一樣,減少了互動,提升了體驗

  此區域也會抛出OutOfMemoryError異常

添加個思維導圖供參考,裡面沒有列出直接記憶體和運作時常量池

JVM運作時記憶體區域劃分