JVM基礎知識簡要概括

JVM初探

jvm體系結構

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RxnI0Mey-1583463998979)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200305170623614.png)]

  • 方法區:存儲 static,final,Class,常量池。

  • 本地方法棧 :用來登記native 方法,最終的執行時,通過JNI加載本地方法庫的方法(java本地接口)

  • java虛擬機棧 : 8大基本類型+對象引用+實例方法

    • 棧內存:主管程序的運行,聲明週期和線程同步,線程結束棧內存釋放,不存在垃圾回收問題

雙親委派機制

類加載器:

  1. BootstrapClassLoader (啓動類加載器):負責加載jre/lib/rt.jar(c++編寫,開發者無法直接獲取啓動類加載器的引用)
  2. ExtClassLoader(擴展類加載器) : 負責加載jre/lib/ext/*.jar(java編寫)
  3. AppClassLoader(應用程序類加載器): 負責加載用戶類路徑(classpath)上指定的類庫。(java編寫)
  4. CustomClassLoader(用戶自定義類加載器) : 加載指定路徑的class文件(java編寫)

工作流程:

  1. 當類加載器收到類加載的請求時,不斷委派父加載器,直到啓動類加載器
  2. 若啓動類加載器能加載,則加載,不能的話,就拋出異常並通知子加載器加載
  3. 重複步驟二;

native

在95年創造java的時候,c和c++已經很流行了,java要佔據一地,使Java也可以調用c,c++的程序,這就是native

native標記的 代表是非java編寫的,會回去調用底層的c語言庫,進入本地方法棧。

jvm在內存管理中開闢了一塊標記區域:本地方法棧 用來登記native 方法,最終的執行時,通過JNI加載本地方法庫的方法

new一個對象的過程

new一個對象分爲,加載並初始化創建一個對象兩個步驟,如果第一個步驟已經走過了,那麼就會直接執行第二步;

如果沒有則會進行類的加載和初始化:

  • 類的加載: 分爲加載和連接兩部分其中連接包括(驗證,準備,解析)

    1. 加載: jvm找到對應的class文件,以二進制字節流的形式讀取到jvm方法區中。
    2. 驗證:總的來說就是檢查是否符合java規範
      1. 是否符合Class文件規範
      2. 是否符合java語法(final標記的類是否有子類,final方法是否被重寫等)
    3. 準備:爲其靜態變量分配空間並設置一個初始值,如果是靜態常量則直接被賦值
    4. 解析:將符號引用轉換爲直接引用,和靜態綁定(private,final,static 的方法與類和對象關聯起來)
      • 符號引用 : java類並不知道所引用類的實際地址用符號引用代替
      • 直接引用 : 直接指向目標的指針
      • 靜態綁定: 所有不會被重寫的方法和域都會被靜態綁定
  • 初始化的過程(先父後子)

    • 靜態變量賦值 和 執行靜態代碼塊
  • 創建對象

    • 在堆區爲其分配空間(分配的內存包括本類和父類的所有實例變量,但不包括任何靜態變量)
  • 對所有實例變量賦默認值 ( 將方法區內對實例變量的定義拷貝一份到堆區,然後賦默認值)

    • 執行實例初始化代碼

      • 初始化順序是先初始化父類再初始化子類,初始化時先執行實例代碼塊然後是構造方法
  • 在棧區定義引用變量,然後將堆區對象的地址賦值給它

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gLvQV1c0-1583463998980)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200306091811802.png)]

jdk1.8後,常量池,被分離出來,和元空間一起,邏輯上屬於堆,物理上卻不屬於

VM調優參數 :-Xmx2048m -Xms1024m -XX:+PrintGCDetails(壓制警告)

​ :-Xmx8m -Xms4m -Xlog:gc*(代替上面的gc參數)

-Xmx表示運行時最大可佔用的內存(默認1/4)

-Xms程序啓動時佔用的內存(默認1/64)

默認經歷15次GC沒有被回收,進入養老區。

GC

GC主要是對堆和方法區進行的,程序計數器,虛擬機棧和本地方法棧都是線程私有的,隨線程消失而消失不需要回收。

由上圖知:堆中分爲新生區和老年區

新生區: 伊甸園 :倖存區(to) : 倖存區(from) = 8 : 1: 1

  • 伊甸園 : 絕大部分剛創建的對象就存儲在伊甸園區
  • 倖存一區 : 在伊甸園空間執行第一次GC(Minor GC)之後,存活的對象被移動到其中一個倖存者空間(Survivor)。每一次gc後存活的對象就會被移到同一個倖存區(to)
  • 倖存二區 : 當一個倖存者空間飽和,還在存活的對象會被移動到另一個倖存者(from)空間。然後會清空已經飽和的哪個倖存者空間。 清空的區就變成from區,from就變成了to區;
  • 在以上步驟中重複N次(N = MaxTenuringThreshold(年齡閥值設定,默認15))依然存活的對象,就會被移動到老年代

垃圾回收算法

  1. 標記清除法

    • 標記階段 : 程序會檢查每個對象是否爲活動對象,如果是活動對象,則程序會在對象頭部打上標記。
    • 清除階段 : 對對象進行回收並取消標誌位,並判斷與前一個空閒分塊是否連續,連續則合併。 (回收就是,將次分塊連接到空閒鏈表中)
    • 分配 : 搜索空閒鏈表,找到大於或等於新對象size的塊。

    不足:

    • 標記和清除過程效率都不高;
    • 會產生大量不連續的內存碎片,導致無法給大對象分配內存。
  2. 標記整理法

    • 讓所有存活的對象都向一端移動,然後直接清理掉端邊界以外的內存。

    優點 : 避免產生內存碎片

    不足 : 需要大量移動對象,效率低

  3. 複製法

    • 將內存分爲兩塊,每次使用其中的一半,使用後若該對象存活則複製到另一半空間中,並釋放剛剛使用的空間中的對象。

    不足: 內存只有一半了。

  4. 分代收集

    • 新生代使用:複製算法
    • 老年代使用:標記 - 清除 或者 標記 - 整理 算法

JMM(java內存模型)

什麼是Volatile

Volatile是Java虛擬機 提供的 輕量級同步機制,是關鍵字。

  • 保證可見性
  • 不保證原子性
  • 禁止指令重排

什麼是JMM

JMM: Java內存模型,不存在,概念,約定;

關於JMM的一些同步約定

  • 線程解鎖前,必須把共享變量立刻寫回。
  • 線程加鎖前,必須讀取主存中最新值到工作內存。
  • 加鎖解鎖是同一把鎖。

內存交互操作有8種,虛擬機實現必須保證每一個操作都是原子的,不可在分的(對於double和long類型的變量來說,load、store、read和write操作在某些平臺上允許例外)

  • lock (鎖定):作用於主內存的變量,把一個變量標識爲線程獨佔狀態

  • unlock (解鎖):作用於主內存的變量,它把一個處於鎖定狀態的變量釋放出來,釋放後的變量纔可以被其他線程鎖定

  • read (讀取):作用於主內存變量,它把一個變量的值從主內存傳輸到線程的工作內存中,以便隨後的load動作使用

  • load (載入):作用於工作內存的變量,它把read操作從主存中變量放入工作內存中

  • use (使用):作用於工作內存中的變量,它把工作內存中的變量傳輸給執行引擎,每當虛擬機遇到一個需要使用到變量的值,就會使用到這個指令

  • assign (賦值):作用於工作內存中的變量,它把一個從執行引擎中接受到的值放入工作內存的變量副本中

  • store (存儲):作用於主內存中的變量,它把一個從工作內存中一個變量的值傳送到主內存中,以便後續的write使用

  • write  (寫入):作用於主內存中的變量,它把store操作從工作內存中得到的變量的值放入主內存的變量中

JMM對這八種指令的使用,制定瞭如下規則:

  • 不允許read和load、store和write操作之一單獨出現。即使用了read必須load,使用了store必須write
  • 不允許線程丟棄他最近的assign操作,即工作變量的數據改變了之後,必須告知主存
  • 不允許一個線程將沒有assign的數據從工作內存同步回主內存
  • 一個新的變量必須在主內存中誕生,不允許工作內存直接使用一個未被初始化的變量。就是懟變量實施use、store操作之前,必須經過assign和load操作
  • 一個變量同一時間只有一個線程能對其進行lock。多次lock後,必須執行相同次數的unlock才能解鎖
  • 如果對一個變量進行lock操作,會清空所有工作內存中此變量的值,在執行引擎使用這個變量前,必須重新load或assign操作初始化變量的值
  • 如果一個變量沒有被lock,就不能對其進行unlock操作。也不能unlock一個被其他線程鎖住的變量
  • 對一個變量進行unlock操作之前,必須把此變量同步回主內存
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章