02.JVM-內存模型

內存模型圖解概覽

image

image

對於圖上參數的控制java

  • -Xms設置堆的最小空間大小
  • -Xmx設置堆的最大空間大小
  • -XX:NewSize設置新生代的最小空間大小
  • -XX:MaxNewSize設置新生代的最大空間大小
  • -XX:PermSize設置永久代的最小空間大小
  • -XX:MaxPermSize設置永久代的最大空間大小

沒有直接設置老年代的參數,可是能夠設置堆空間大小和新生代空間大小兩個參數來間接控制。算法

老年代空間大小=堆空間大小-年輕代大空間大小
複製代碼

jvm和系統調用之間的關係bash

image

各個區域的做用和詳解

java堆(Heap)

圖解 多線程

image

  • 堆內存是java虛擬機所管理的內存中最大的一塊,
  • 被全部線程共享的內存區域,
  • 在虛擬機啓動的時候建立,
  • 存放的是對象的實例,幾乎全部的對象實例都在這裏分配內存
  • 是垃圾收集器管理的主要區域,也被稱之爲「GC堆」
  • 堆分爲新生代和舊生代,各自所佔的比例爲新生代爲1/三、舊生代2/3,新生代存儲的是剛建立的對象、比較小的對象。舊生代存儲的爲較大的對象、存活時間較長的對象
  • 新生代能夠細分爲:Eden空間、From Survivor空間、To Survivor空間,各自所佔的比例爲8:1:1
  • 根據java虛擬機規定,java堆能夠處在物理上不連續的內存空間,只要是邏輯上是連續的便可
  • 堆中沒有內存完成實例的分配,而且堆也沒法再擴展時,將會拋出OutOfMemoryError(OOM)異常。

將一個類進行初始化的過程示例,對象A建立後,在堆內存的分配和流轉jvm

  • 當對象A被new出來的時候,存在放Eden區
  • 當第一次放生GC後,Eden區存活下來的對象A會被複制到To Survivor區,同時From Survivor區的對象也會被複制到To Survivor區
  • GC會清空Eden區和From Survivor區中的全部存儲對象,由於以前已經將對象複製了,因此能夠徹底清除
  • To Survivor和From Survivor會交換角色,要保證在GC發生以前,To Survivor永遠是空的那個
  • 下次GC發生時,重複上述步驟。將Eden中存活的對象複製到To Survivor,將From Survivor中活的對象也複製到To Survivor。
  • 發生GC時,From Survivor中存活的對象並非所有都會被複制到To Survivor中,而是根據這個對象在Survivor區中存活了多久而決定去向,當一個對象在Survivor中存活了好久(即經歷了屢次GC還沒死),就會在發生GC時被複制到舊生代中。

堆內存分配策略明確如下三點:spa

  1. 對象優先在Eden分配。線程

  2. 大對象直接進入老年代。3d

  3. 長期存活的對象將進入老年代。code

爲何對象在新生代中複製來複制去的,而不是將死的直接清除,老的直接複製到舊生代 這樣作的好處就是減小了內存碎片,而直接清除的話會使內存很零碎。詳情能夠了解一下java垃圾回收算法中的複製算法orm

方法區 (Method Area)

有一個別名叫作Non-Heap(非堆),目的應該是與Java堆區分開來

存儲的內容

image

  • 各個線程共享的內存區域
  • 存儲已經被虛擬機加載的類信息,常量,靜態變量,既時編譯器編譯後的代碼等數據
  • 有人也稱其爲永久代,可是二者並不等價
  • 不需連續的內存,能夠選擇固定大小,能夠選擇擴展,能夠選擇不實現垃圾收集
  • 並不是數據進入了方法區就如永久代的名字同樣「永久」存在了。這個區域的內存回收目標主要是針對常量池的回收和對類型的卸載,通常來講這個區域的回收「成績」比較難以使人滿意,尤爲是類型的卸載,條件至關苛刻,可是這部分區域的回收確實是有必要的。
  • 當方法區沒法知足內存分配需求時,將拋出OutOfMemoryError異常。
  • 方法區有時被稱爲持久代(PermGen)。
程序計數器(Program Counter Register)
  • 程序計數器是一塊較小的內存空間,能夠看作當前線程所執行的字節碼行號指示器
  • 能夠稱之爲PC寄存器
  • 字節碼解釋器在工做的時候,經過改變程序計數器的值,來選取下一條須要執行的字節碼指令、分支、循環、跳轉、異常處理、線程恢復等基礎功能,都須要依賴於這個計數器完成
  • 此內存區域是惟一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域。
  • 每條線程都有以及一個獨立的線程計數器
  • java方法:這個計數器記錄的是正在執行的虛擬機字節碼指令的地址
  • Native方法:計數器值爲空(Undefined)
  • PC寄存器是對物理PC寄存器的一種抽象模擬,線程私有,生命週期與線程的生命週期保持一致

程序計數器爲何是線程私有

所謂的多線程在一個特定的時間段內只會執行其中的某一個線程方法,CPU會不停的切換任務,爲了可以準確的記錄各個線程正在執行的當前字節碼地址,最好的辦法是每個線程都分配一個PC寄存器,這樣一來每個線程都能獨立運算,不會出現相互干擾

JAVA 棧(jvm stacks)
  • java棧屬於線程私有,他的生命週期和線程相同
  • jvm stacks描述的是java方法執行的內存模型:每個方法執行的時候,都會同時建立一個棧幀,用於存儲局部變量表,操做棧,動態連接,方法出口等信息
  • 每個方法從被調用直至執行完成的過程,就是對應的一個棧幀在虛擬機中入棧到出棧的過程
  • 棧幀的概念結構
本地方法棧(Native Method Stacks)
  • 本地方法棧和虛擬機棧發揮的功能很是類似,區別就是虛擬機棧爲虛擬機執行java方法服務,本地方法棧則是爲虛擬機使用到的Native方法服務
  • 本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。
相關文章
相關標籤/搜索