JVM那些事兒,這些必會的知識點(一)

我是方圓,一邊做課程設計,一邊更博客

在這裏插入圖片描述

在這裏插入圖片描述

1. native關鍵字(瞭解)

Java無法直接訪問系統的底層(我們熟悉的啓動線程中start0()方法就是被native關鍵字修飾),所以,引入native關鍵字對Java實現擴展,通過JNI(Java Native Interface)接口調用其他語言(如C和C++),實現對底層的訪問。

2. 方法區

方法區中存在靜態變量常量類信息運行時常量池存在方法區中,但是實例變量存在堆內存中,和方法區無關。(static,final,Class,常量池)

3. 棧

棧中保存的是八大基本類型,對象的引用

4. 類的加載過程

類的生命週期如下圖所示

在這裏插入圖片描述

  1. 加載
    在加載階段,我們可以參考java.lang.ClassLoader中的loadClass()方法,會在方法區中生成一個代表這個類的java.lang.Class對象,作爲方法區這個類的各種數據的訪問入口
  2. 驗證
    這個階段主要確保了Class文件的字節流中包含的信息符合虛擬機的要求,並且不會危害虛擬機的安全。驗證是非常重要的,但是不是必須的,它對程序運行期沒有影響
  3. 準備
    準備階段是正式爲類變量(static)分配內存並設置初始值的階段,這些變量所使用的內存都在方法區中分配。
  4. 解析
    解析階段是虛擬機將常量池內的符號引用替換爲直接引用的過程。
  5. 初始化
    這個階段是類加載過程的最後一步。在準備階段,我們已經對類變量賦值過(初始0值),而在這個初始化階段,則根據我們寫的代碼去初始化變量和其他資源。或者說,初始化階段是執行類構造器<clinit>()方法的過程。<clinit>()方法是由編譯器自動收集類中所有的類變量賦值語句靜態代碼塊中的賦值語句所產生的。
    虛擬機會保證一個類的類構造器<clinit>()在多線程環境中被正確的加鎖、同步,如果多個線程同時去初始化一個類,那麼只會有一個線程去執行這個類的類構造器<clinit>(),其他線程都需要阻塞等待,直到活動線程執行<clinit>()方法完畢。需要特別注意的是,其他線程雖然會被阻塞,但是當<clinit>()執行完畢,其他線程被喚醒之後不會再去執行這個方法,因爲在同一個類加載器下,一個類型只會被初始化一次

5. 對象的實例化過程

實例化一個類的對象,是一個典型的遞歸過程,如下圖所示。

在這裏插入圖片描述

在準備實例化一個對象前,首先會準備實例化該類的父類,如果該類的父類還有父類,那麼還會向上實例化,直到遞歸到Object類。實例化Object類之後,再依次向下對各類進行實例化。

5.1 舉一個小例子

Student student = new Student();
  1. 當虛擬機遇到一條new命令的時候,先檢查方法區中是否存在該對象的類信息,並且檢查該類是否被加載、解析和初始化
    (1)如果方法區中沒有該類的信息,那麼會拋處ClassNotFoundException
    (2)若以上的檢查全部通過,則進入下一步工作
  2. 類加載完成後,虛擬機將爲新生對象分配內存
  3. 從堆中劃分一塊兒相應大小的內存給新的對象
  4. 爲新對象的成員變量附上初始值
  5. 設置並保存對象頭信息(Object Header),對象頭信息包括該對象是哪個類實例、對象的哈希碼、對象的 GC 分代年齡等信息
  6. 一般來說,執行 new 指令之後會接着執行 方法,把對象按照程序員規定的構造函數進行初始化

6. 堆

在這裏插入圖片描述
中存放的是對象,包含年輕代和老年代,永久代(在jdk1.8被元空間取代)中包含方法區

6.1 分代概念

新生成的對象首先放到年輕代Eden區,當Eden空間滿了,觸發Minor GC,存活下來的對象移動到Survivor0區,Eden再次填滿後觸發執行Minor GC,Survivor0區存活對象移動到Suvivor1區,這樣保證了一段時間內總有一個survivor區爲空(空的爲to,非空的爲from)。經過15次Minor GC仍然存活的對象移動到老年代。
老年代存儲長期存活的對象,佔滿時會觸發Major GC=Full GC,GC期間會停止所有線程等待GC完成,所以對響應要求高的應用盡量減少發生Major GC,避免響應超時。

  • Minor GC : 清理年輕代
  • Major GC : 清理老年代
  • Full GC : 清理整個堆空間,包括年輕代和永久代
    在這裏插入圖片描述

6.2 爲什麼分代?

將對象根據存活概率進行分類,對存活時間長的對象,放到固定區,從而減少掃描垃圾時間及GC頻率。針對分類進行不同的垃圾回收算法,對算法揚長避短。

6.3 爲什麼survivor分爲兩塊相等大小的倖存空間?

主要爲了解決碎片化。如果內存碎片化嚴重,也就是兩個對象佔用不連續的內存,已有的連續內存不夠新對象存放,就會觸發GC。

6.4 JVM堆內存中常用參數

參數 描述
-Xms 堆內存初始化大小
-Xmx 堆內存最大允許大小,一般不超過物理內存的80%
-XX:+PrintGCDetail 打印GC詳細信息
-XX:PermSize 非堆內存初始大小,一般設置200M
-XX:MaxPermSize 非堆內存允許的最大大小
-Xns 年輕代內存初始化大小
-Xmn 年輕代內存允許的最大內存大小
-XX:SurvivorRatio=8 Eden區與Survivor區的容量比值,默認爲8
-Xss 棧內存大小

在這裏插入圖片描述

同系列

JVM那些事兒,GC(二)

參考文獻

JVM類生命週期概述:加載時機與加載過程

深入理解Java對象的創建過程:類的初始化與實例化

JVM 虛擬機與對象創建過程

Java堆內存又溢出了!教你一招必殺技

【狂神說Java】JVM快速入門篇

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