十個問題弄清JVM&GC(一)

每一個java開發同窗不論是平常工做中仍是面試裏,都會遇到JDK、JVM和GC的問題。本文會從如下10個問題爲切入點,帶着你們一塊兒全面瞭解一下JVM的方方面面。java

  1. JVM、JRE和JDK的區別和聯繫
  2. JVM是什麼?以及它的主要做用
  3. JVM的核心功能有哪些
  4. 類加載機制和過程
  5. 運行時數據區的邏輯結構
  6. JVM的內存模型
  7. 如何肯定對象是垃圾
  8. 垃圾收集的算法有哪些
  9. 各類問世的垃圾收集器
  10. JVM調優的參數配置

一、JVM、JRE和JDK的區別和聯繫

這個基本是步入java世界的入門級知識認知,首先咱們來看一下來自java官網的一張圖:面試

從這張圖裏咱們基本就能夠看出「JRE」是運行Java語言編寫的程序所不可缺乏的運行環境。有了JRE咱們寫的java程序才能夠運行起來被用戶所使用。

而「JDK」俗稱java開發工具包,它包括了Java運行環境JRE(Java Runtime Envirnment)以及一堆Java工具(javac/java/jdb等)和Java基礎的類庫(即Java API 包括rt.jar)。算法

但不論是JRE仍是JDK都是以JVM爲基石的。能夠說JVM是java程序能夠在某臺機器上得以運行的最底層的保障。數組

二、那麼什麼是JVM?它的主要做用又是什麼?

JVM是Java Virtual Machine(Java虛擬機)的縮寫,它的用途簡單的說就是它能讓咱們寫的java程序在不一樣的操做系統的不一樣CPU上運行。咱們寫的java程序會利用開發工具(如Intellij idea)把它編譯成.class文件,但這個class文件是不能直接被操做系統識別運行的,須要利用jvm按jvm規範將編譯好的.class文件轉變成機器語言,再交由操做系統提交給cpu去執行。jvm

用一句話評價JVM的主要做用就是:JVM屏蔽了與具體操做系統平臺相關的信息,使得Java程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就能夠在多種平臺上不加修改地運行。ide

三、這麼牛的JVM的核心功能有哪些?

JVM中核心的功能整體有三塊:工具

  1. 類加載器:在JVM啓動時或者在類運行時將須要的class文件加載到JVM中
  2. 執行引擎:負責執行class文件,包括分配運行時數據區(如程序計數器、本地方法棧和虛擬棧)和 最終將class中的字節碼指令轉爲機器指令經過操做系統交給CPU執行
  3. 垃圾回收器:對JVM的堆內存進行管理,及時回收調無用的資源釋放內存空間

四、JVM類的加載機制和過程?

首先,咱們談談開發工具編譯生成的class文件是如何被JVM加載的。所謂的類加載機制其實就是:虛擬機(JVM)把class文件加載到內存中,而後對它進行正確性的校驗,檢查經過再進行解析和初始化,最終把class文件變成一個內存中能夠直接使用的java.lang.Class對象。開發工具

從一個class文件的裝載到銷燬,它的生命週期基本能夠分爲如下五個階段:裝載、連接(驗證、準備和解析)、初始化、使用和卸載。優化

  1. 裝載:裝載(Load)階段總共有三項工做idea

    (1)經過類的全限定名獲取其定義的二進制字節流,須要藉助類裝載器(ClassLoader)完成;

    (2)在運行時數據區的「方法區」中分配一塊區域保存這個類的信息,包括類的基本信息、常量和靜態變量等等;

    (3)在「Java堆」內存上生成一個該類的java.lang.Class對象,用於對外暴露使用該類的入口。

  2. 連接:連接(link)階段一樣有三項工做

    (1)驗證(Verify),驗證文件格式、元數據、字節碼和符號引用,以保證被加載類的準確性;

    (2)準備(Prepare),爲靜態變量分配內存並初始化爲默認值。

    (3)解析(Resolve),解析階段是虛擬機將常量池內的符號引用替換爲直接引用的過程。解析動做主要針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調用限定符7類符號引用進行。

  3. 初始化:初始化(Initialize)階段所作的工做就是對類的靜態成員變量和靜態方法進行初始化賦值或調用。

好比上面的靜態變量age初始化以後的值變爲了10。

在裝載階段的第(2),(3)步能夠發現有運行時數據區,堆,方法區等名詞,那麼究竟什麼是「運行時數據區」,它有哪些結構構成?

五、什麼是JVM運行時數據區?及其邏輯結構

「運行時數據區」是JVM在執行Java程序的過程當中出於內存管理方面的目的,在設計上把內存分爲若干個不一樣的區域。這些區域有着各自的用途,有的區域生命週期跟虛擬機同樣,隨着虛擬機進程的啓動而存在,伴隨這虛擬機的進程結束而消亡。而有些區域則依賴用戶線程的啓動和結束而創建和銷燬。具體以下圖:

  1. 方法區(Method Area): (1)用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據;

(2)方法區是各個線程共享的內存區域,在虛擬機啓動時建立,由於同一個class類信息只須要加載一份就夠了;

(3)java虛擬機規範中把方法區描述爲堆內存的一個邏輯部分,但它有另一個別名叫「非堆」,用於與java堆區分開來。在JDK8以前方法區叫作Perm space,在JDK8及之後叫作Metaspace(即元數據區)。

  1. 堆(Heap):Java堆是被全部線程共享,虛擬機啓動時建立,此內存區域惟一的目的就是存放對象實例,在Java虛擬機規範中的描述是:全部的對象實例以及數組都要在堆上分配,可是隨着JIT編譯器的發展和逃逸分析技術逐漸成熟,棧上分配,標量替換優化技術將會致使一些微妙的變化發生,全部的對象都分配在堆上也就變得不那麼絕對了。

  2. 虛擬機棧(Java Virtual Machine Stacks):虛擬機棧是線程私有的或者說是獨有的,隨着線程的建立而建立。一個線程的運行狀態(正在調用哪一個方法),就是由這個線程對應的虛擬機棧來保存的。

每個被線程執行的方法,爲虛擬機棧中的一個棧幀,調用一個方法,就會向棧中壓入一個棧幀;一個方法調用完成,就會把該棧幀從棧中彈出。以下圖解:

  1. 程序計數器(The Pc Register):咱們都知道一個JVM進程中有多個線程在執行,而線程中的內容是否可以擁有執行權,是根據CPU調度來的。假如線程A正在執行到某個地方,忽然失去了CPU的執行權,切換到線程B了,而後當線程A再得到CPU執行權的時候,怎麼能繼續執行呢?這就是須要在線程中維護一個變量,記錄線程執行到的位置,這就是程序計數器。

  2. 本地方法棧(Native Method Stacks):本地方法棧與虛擬機棧所發揮的做用很是類似,他們之間的區別不過是虛擬機棧爲虛擬機執行Java方法(字節碼)服務,而本地方法棧則爲虛擬機中使用到的native方法服務。即若是當前線程執行的方法是Native類型的,這些方法就會在本地方法棧中執行。

總結一下,就JVM的設計規範,從使用用途角度JVM的內存大致的分爲:線程私有內存區 和 線程共享內存區。

線程私有內存區在類加載器編譯某個class文件時就肯定了執行時須要的「程序計數器」和「虛擬棧幀」等所需的空間,而且會伴隨着當前執行線程的產生而產生,執行線程的消亡而消亡,所以「線程私有內存區」並不須要考慮內存管理和垃圾回收的問題。

線程共享內存區在虛擬機啓動時建立,被全部線程共享,是Java虛擬機所管理內存中最應該關注的和最大的一塊。

那麼JVM內存模型是如何設計的?JVM又是如何進行內存管理(也就是垃圾回收)的?垃圾回收算法有哪些?目前經常使用的垃圾回收器又有哪些?我會在下篇文章跟您共同解答這些問題。

做者:宜信技術學院 譚文濤

相關文章
相關標籤/搜索