Java 運行內存學習筆記

虛擬機

Java虛擬機(Java Virtual Machine)是用來屏蔽底層硬件的,它負責把字節碼(*.class)文件翻譯成機器碼,從而達到跨平臺的目的。

java源代碼先通過編譯器編譯成class文件,再經過特定的JVM(不同的操作系統下JVM不同)翻譯成操作系統能看懂的機器碼。因此JVM不侷限於Java語言,它面向的是一個字節碼規範,如果能把其它語言代碼(如PHP)編譯成正確的Class文件,JVM也是可以運行的。

Java虛擬機,顧名思義它是一個虛擬機,虛擬機和普通PC一樣能運行程序,PC機運行程序所必要的因素JVM也需要滿足。

內存結構

內存分五個部分:

  1. 堆內存
  2. 方法區
  3. 虛擬機棧
  4. 本地方法棧
  5. 程序計數器 

內存分類

分成兩部分

線程私有部分:虛擬機棧、本地方法棧、程序計數器

線程共享部分:堆內存、方法區

 

堆內存

堆內存隨虛擬機創建而創建,是佔用內存最多的,也是Gc(垃圾回收器是一個運行在堆(heap)上的一個線程)回收的主要內存,它用來存放創建的對象。由於幾乎所有的對象都要在堆上創建,所以它是線程共享的,所有線程創建的對象都要在同一個堆上面(如果堆線程私有,那麼意味着每個線程都有自己的堆,首先會很浪費內存,再者這樣也會加大線程間通信的難度)。

堆內存細分成年輕代(Young Gen)和老年代(Old Gen),它們的比例是1比2,堆內存如果是30MB,年輕代佔10MB,老年代佔20MB。

年輕代細分爲Eden區,From區(Survivor0),To區(Survivor1),它們的比例是8:1:1,From和To只使用一個,另一個是作爲一個臨時容器使用的,因此只有90%的內存可以使用。

java線程創建一個對象時,會首選存到Eden區,如果內存不足則會觸發MinorGc(年輕代內存回收),Gc從Gc-root開始遍歷找到所有有引用的對象,第一次把它們複製到其中一個區,例如From區,並對每個對象進行計數。

第二次再觸發MinorGc時,再從Gc-root遍歷一次,把Eden和From區的有效對象移動到To區(因爲上一次是放到了From區),再清空Eden和From,並且把對象計數再加1,如此反覆,默認加到16的時候會移動到老年區(可以通過啓動參數修改)。

這樣做的好處是From和To中的內存都是連續的,不擔心碎片過多導致無法創建大對象的問題。

直到老年代內存不足時會觸發MajorGc,會對老年代進行垃圾回收,但是老年代只有一個內存塊,沒有臨時的(類似From和To),因此只能使用標記壓縮回收的方式進行回收,且老年代內存塊最大,因此效率較低,由於執行Gc時,會觸發Stop-The-World,線程不能訪問內存對象,導致客戶端響應慢。

還有一種Gc叫做fullGc,根據名稱可以知道它是既回收Young Gen又回收Old Gen的。

方法區

也叫靜態區,用來存放類信息、靜態變量、方法數據、方法代碼等。線程需要創建對象時,需要從這裏獲取信息,存放的都是在整個程序中永遠唯一的元素,因此它也是線程共享的。

虛擬機棧

棧是一種數據結構,不管它叫什麼棧,都是先入後出(FILO)的,都是用於存數據的。在這裏只是存了方法調用的臨時變量而已。

每個線程有一個私有的棧,隨着線程的創建而創建。棧裏面存着“棧幀”,每調用一個方法會創建一個棧幀,棧幀中存放了局部變量表(基本數據類型和對象引用)、操作數棧、方法出口等信息。棧的大小可以固定也可以動態擴展。當棧調用深度大於JVM所允許的範圍,會拋出StackOverflowError的錯誤(多是因爲遞歸造成)。

虛擬機棧是用來執行方法用的,當調用一個方法時,會創建一個棧幀,棧幀壓入虛擬機棧頂,如果此方法又調用另一個方法,則會再創建一個棧幀壓入棧頂,如此循環,因此在查看代碼拋出異常時是反着的,從下向上纔是調用的順序。

public class Test {
  
  public static void main(String [] args) {
    A();
  }

  public static void A() {
    B();
  }

  public static void B() {
    C();
  }

  public static void C() {
    D();
  }

  public static void D() {
  }
  
}

本地方法棧

用來調用Native方法的,如果是純java則不需要使用這部分。

程序計數器

用來記錄當前線程正在執行的行號,因爲多線程是需要搶佔CPU資源的,當線程被掛起之後在下一次喚醒之前,需要有一個變量來記錄當前執行的位置,以便再次搶到CPU資源後繼續執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章