入門JAVA必須了解的基礎知識-JVM

碼農聊it 發佈 2023-03-20T11:32:34.958623+00:00

JAVA虛擬機(JVM)JVM內存模型 JVM包含兩個子系統和兩個組件:類裝載系統和執行引擎系統,運行時數據區和本地接口。如同一台真實的機器,有自己的指令集和執行引擎,可以在運行時操控內存區域,可以解讀指令代碼並與系統底層進行交互。

  1. java虛擬機(JVM)

JVM包含兩個子系統和兩個組件:類裝載系統和執行引擎系統,運行時數據區和本地接口。如同一台真實的機器,有自己的指令集和執行引擎,可以在運行時操控內存區域,可以解讀指令代碼並與系統底層進行交互。

首先由編譯器將JAVA代碼轉換成字節碼,再由類加載器將字節碼加載到內存中,保存在運行時數據區的元數據區內。字節碼是Java虛擬機特定的一套指令集規範,作業系統無法識別運行,需經過JAVA虛擬機特定的執行引擎翻譯成底層作業系統指令,再交由CPU執行。

  • 運行時數據區

java將所管理的內存分為5個區域:元數據,堆,虛擬機棧,本地方法棧和程序計數器。

  1. 元數據:主要用於存儲已經被虛擬機加載的類型信息、常量、靜態變量、即時編譯器編譯後的代碼緩存等。
  2. 堆:JAVA虛擬機內存管理中最大的一塊,幾乎分配保存所有的對象實例,被所有的線程序共享。
  3. 虛擬機棧:用於存儲局部變量,操作數據棧,動態連結,方法出口等信息,由線程私有。
  4. 本地方法棧:與虛擬機棧作用一樣,用於調用其他語言的第三方系統庫接口。
  5. 程序計數器:當前線程所執行的字節碼的行號指示器,通過改變計數器的值,來選取下一行指令,通過它主要實現跳轉、循環、恢復線程等功能。一個CPU同一時刻只能運行一個線程,多線程通過搶占CPU運行,所以每個線程都需有一個標記來指示線程執行到哪裡,以便恢復運行。若執行的是native方法,程序計數器中則為空。

堆和棧的區別:

  • 管理方式,堆需要GC,棧自動釋放
  • 大小不同,堆比棧大
  • 碎片相關:棧產生的碎片遠小於堆,因為GC不是實時的
  • 分配方式:棧支持靜態分配內存和動態分配,堆只支持動態分配
  • 效率:棧的效率比堆的高


  • JAVA虛擬機最大的內存-堆

堆主要存儲了JAVA的實例對象。java提供了5種創建對象方式:

  1. 通過new調用構造函數。
  2. 通過Class的newInstance方法調用構造函數。
  3. 通過Constructor類的newInstance方法調用構造函數。
  4. 通過類的clone方法
  5. 反序列化。

虛擬機接收到一條new創建對象的指令時,先檢查元數據區常量池是否已加載了相應的類,如果沒有則通過類加載器加載,再分配內存, 然後內存空間初始化操作, 最後執行初始化方法。

虛擬機有兩種內存分配方式:

  1. 指針碰撞:如果Java堆的內存是規整,即所有用過的內存放在一邊,而空閒的的放在另一邊。分配內存時將位於中間的指針指示器向空閒的內存移動一段與對象大小相等的距離,這樣便完成分配內存工作。

  2. 空閒列表:如果Java堆的內存不是規整的,則需要由虛擬機維護一個列表來記錄那些內存是可用的,這樣在分配的時候可以從列表中查詢到足夠大的內存分配給對象,並在分配後更新列表記錄。


  • JVM堆及各種GC
  1. JAVA中的堆又可以分為兩大部分:新生代和老年代

新生代:主要是用來存放新生的對象。一般占據堆的 1/3 空間。由於頻繁創建對象,所以新生代會頻繁觸發 MinorGC 進行垃圾回收。

新生代又分為 Eden、S0、S1(SurvivorFrom、SurvivorTo)三個區:

  • Eden 區:Java 新對象的出生地(如果新創建的對象占用內存很大,則直接分配到老年代)。
  • 當 Eden 區內存不夠的時候就會觸發 MinorGC,對新生代區進行一次垃圾回收。
  • SurvivorFrom 區:上一次 GC 的倖存者,作為這一次 GC 的被掃描者。
  • SurvivorTo 區:保留了一次 MinorGC 過程中的倖存者。

Eden 和 S0,S1 區的比例為 8 : 1 : 1

老年代:

新生代的對象經過一次次的Minor GC後仍存活,年齡達到晉升老年代的年齡閾值(MaxTenuringThreshold, 默認:15)或同齡的對象超過新生代的一半,就會被晉升到老年代。老年代的對象都比較穩定,默認的新老年代內存比例為1:2。

在Major GC前一般都會先進行一次Minor GC,使得有新生代的對象晉升老年代,導致空間不夠才觸發的major GC。或者當有大對象創建但找不到足夠的連續內存空間分配時也會觸發一次Major GC。

  • JVM性能調優

java [options] MainClass [arguments]

  1. options: JVM啟動參數。多個參數空格分隔
  2. arguments: 參數賦值。 -參數名=參數值 或 -參數名:參數值

內存參數:

  • -Xms: 初始化堆大小。
  • -Xmx: 最大堆大小。
  • -Xmn:新生代大小。
  • -Xss:每個線程java棧大小。
  • -XX:NewSize=n:年輕代大小。
  • -XX:NewRatio=n:年輕代與老年代的內存比例。默認1:2。
  • -XX:SurvivorRatio:年輕代中Eden區與兩Survivor區的內存比例,默認8:1:1。
  • -XX:MaxTenuringThreshold=n:晉升老年代的最大年齡閾值,默認15。

垃圾回收器參數:

  • -XX:+UseSerialGC:使用串行收集器
  • -XX:+UseParallelGC:年輕代使用並行收集器
  • -XX:+UseG1GC:使用G1收集器
  • -XX:ParallelGCThreads=n:並行收集器收集時可使用的最大線程數
  • -XX:+UseCMSCompactAtFullCollection:老年代啟用壓縮,可能會影響性能但可以消除內存碎片。
關鍵字: