深刻淺出JVM

知識點彙總java

1、JVM內存模型

棧:也叫方法棧,存儲局部變量表,動態連接,方法出口等信息,調用方法執行入棧,方法返回執行出棧。面試

本地方法棧:與方法棧相似,區別是執行native方法使用的是本地方法棧,執行java方法使用的是方法棧。算法

(注:native方法即便用native關鍵字修飾的java方法,目的在於與操做系統進行交互,調用操做系統語言程序。)緩存

程序計數器:保存當前線程所保存的字節碼位置,每一個線程工做時都有一個獨立的計數器,程序計數器只爲java方法服務,執行native方法時,程序計數器爲空。併發

堆:jvm內存管理中最大的一塊,用於存放對象的實例,當對空間不足時,會拋出OOM異常(java.lang.OutOfMemoryError),jvm把堆內存進行分代管理,由垃圾回收器進行對象的回收管理。app

方法區:又叫非堆區,用於存儲已被虛擬機加載的類信息、常亮、靜態變量、編譯器優化後的代碼等數據,jdk1.7的永久代和1.8的materspace都是方法區的一種實現。jvm

棧、本地方法棧、程序計數器是線程獨佔的。工具

堆、方法區是線程共享的。優化

2、Java內存模型(JMM)

JMM須要保證原子性、可見性、有序性,經過如下四種方式:編碼

一、基本數據類型讀或寫(long、double除外):是原子性的。

二、synchronized:經過java的兩個高級字節碼指令monitorenter和monitorexit來保證原子性,

三、volatile:

可見性保證:強制變量的賦值會刷新回主內存,強制變量的讀取會從主內存中從新加載,保證不一樣的線程老是能看到該變量的最新值。
有序性保證:經過指令重排序保證變量讀寫的有序性。
四、happens-bofore原則:

程序順序原則:一個線程內必須保證語義串行性;
鎖規則:同一把鎖的解鎖必須發生在再次枷鎖以前;
傳遞性規則、線程的啓動、中斷、終止規則等。

3、類的加載與卸載

深綠色表示加載過程,淺綠色表示生命週期。

加載:經過類的徹底限定名找到字節碼文件,經過字節碼文件建立class對象。

驗證:圖中始終驗證方法。

準備:爲static修飾的變量分配內存,初始值0或者null。(final不分配,由於在編譯時已經分配)

解析:圖中。

初始化:看圖中解釋,若類的父類沒有初始化,則先初始化父類的靜態塊和靜態變量,只有對類的主動使用時纔會初始化。

初始化的出發條件:建立類實例、訪問類靜態變量或者靜態方法、class.forName()發射加載、某個子類被初始化。
使用:實例化。

卸載:java前三種類加載器的加載的類不會被卸載,用戶自定義類加載器加載的類纔會被卸載。

4、類加載器與加載模式

類加載器:啓動類加載器、擴展類加載器、應用/系統加載器、用戶自定義加載器。

雙親委派模式好處:

避免類的重複加載;
防止java系統類被篡改。

5、內存分代回收

年輕代:大部分對象會在Eden區生成,Eden區滿時,會在s1和s2中交替保存,達到必定次數對象會晉升到老年代。

老年代:存儲由年輕代晉升到老年代存儲時間較長的內存對象。

永久代:主要保存類信息等內容。(這裏只是一種劃分方式,並非特指1.7 PermGen/1.8 Metaspace)

6、垃圾回收算法判斷算法:

引用計數法
可達性分析算法
清除算法:

引用計數算法:經過對象被引用的次數肯定對象是否被使用,缺點是沒法解決循環引用的問題。
複製算法:分爲from塊和to塊,開始在from塊,回收時將from塊存活的對象複製到to塊,將from塊清空,to塊變from塊,from塊變to塊,缺點是內存使用率較低。
標記清除算法:分爲標記對象和標記不在使用的對象兩個階段,缺點是會產生內存碎片。
標記整理算法:與標記清除算法相同,不過在清楚後會進行內存整理。
分代回收算法:當前的商業虛擬機的垃圾收集都是採用「分代收集」(Generational Collection)算法,這種算法並無什麼新的思想,只是根據對象存活週期的不一樣將內存劃分爲幾塊。通常是把堆劃分爲新生代和老年代,這樣就能夠根據各個年代的特色採用最適合的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少許存活,那就採用複製算法,只須要付出少許存活對象的複製成本就能夠完成收集。而老年代中由於對象存活率高、沒有額外空間對它進行分配擔保,就必須使用「標記-清理」或者「標記-整理」算法來進行回收
jvm提供的年輕代回收算法屬於複製算法,CMS、G1,ZGC屬於標記清除算法。

6.1 CMS算法

CMS是標記清除算法,JDK1.7以前的默認垃圾回收算法,併發收集,停頓小。

初始標記(STW):標記GC roots直接可達的對象。
併發標記:GC線程應用線程併發進行,主要標記可達的對象。
從新標記(STW):停頓時間比並發標記小不少,比初始標記稍長,主要是重新掃描並標記。
併發清理:併發執行,開始清理未標記的對象。
併發重置:爲下一次GC充值相關數據。

6.2 G1算法

G1算法JDK1.9以後默認回收算法,特色是保持高回收率的同時,減小停頓。

年輕代回收:採用複製算法。
老年代回收:採用標記清除算法,同時也會回收年輕代。
G1能夠經過設置JVM參數設置rejion(區)的大小,範圍是1~32M,還能夠設置指望的最大停頓時間。

6.3 ZGC算法

ZGC針對大內存的回收,能夠控制在10ms之內的停頓。

着色指針
讀屏障
併發處理
基於Rejion
內存壓縮(整理)
ZGC GC過程:

面試考察點與真題

一、JVM內存模型、JMM內存模型

二、類加載過程、雙親委派機制

三、原子性、可見性、有序性的保證機制

四、G1適合對最大延遲有要求的場合,ZGC適合64位對大內存有要求的場合

五、垃圾回收的併發數,偏向鎖的設置

 

一、棧上分配釋放壓力,如何編寫適合內聯優化的代碼

二、常常fullGC的問題,內存泄漏問題

三、

四、

 

一、見上

二、年輕代晉升、老年代空間不足、永久代空間不足

三、見上

四、見上

五、見上

六、見上

 

七、強制主內存讀寫同步,防止指令重排序

十、

強引用:不會被GC回收

弱引用:每次GC都會被回收

虛引用:必須和引用兌現聯合使用,跟總一個對象被垃圾回收的過程

軟引用:空間不足會被GC回收

強引用:

只要引用存在,垃圾回收器永遠不會回收

Object obj = new Object();

可直接經過obj取得對應的對象 如obj.equels(new Object());
而這樣 obj對象對後面new Object的一個強引用,只有當obj這個引用被釋放以後,對象纔會被釋放掉,這也是咱們常常所用到的編碼形式。

軟引用:

非必須引用,內存溢出以前進行回收,能夠經過如下代碼實現:

Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;
sf.get();(經過get獲取這個對象,因爲obj指向了null,回收的時候會回收這個obj對象,可是若是尚未來得及回收,能夠取得這個對象,若是已經回收了會返回null)

這時候sf是對obj對象的一個軟引用,經過sf.get()方法能夠取到這個對象,固然,當這個對象被標記爲須要回收的對象時,則返回null;
軟引用主要用於實現相似緩存的功能,在內存足夠的狀況下直接經過軟引用取值,無需從繁忙的真實來源查詢數據,提高速度;

當內存不足時,自動刪除這部分緩存數據,從真正的來源查詢這些數據。

弱引用:

第二次垃圾回收時回收,能夠經過以下代碼實現

Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
wf.get();//有時候會返回null
wf.isEnQueued();//返回是否被垃圾回收器標記爲即將回收的垃圾

弱引用是在第二次垃圾回收時回收,短期內經過弱引用取對應的數據,能夠取到,當執行過第二次垃圾回收時,將返回null。
弱引用主要用於監控對象是否已經被垃圾回收器標記爲即將回收的垃圾,能夠經過弱引用的isEnQueued方法返回對象是否被垃圾回收器標記。

虛引用:

垃圾回收時回收,沒法經過引用取到對象值,能夠經過以下代碼實現

Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
obj=null;
pf.get();//永遠返回null
pf.isEnQueued();//返回是否從內存中已經刪除

虛引用是每次垃圾回收的時候都會被回收,經過虛引用的get方法永遠獲取到的數據爲null,所以也被成爲幽靈引用
虛引用主要用於檢測對象是否已經從內存中刪除

十一、

JMC:飛行計數器

MAT:堆分析工具

JStack:線程分析工具

相關文章
相關標籤/搜索