【JVM專題】JVM從概述到調優圖文詳解,含思維腦圖深度剖析!

前程有光發表於2020-12-15

JVM概述

JVM 是一種用於計算機裝置的規範,它是一個虛構的計算機的軟體實現,簡單的說,JVM 是執行 byte code 位元組碼程式的一個容器。

它有一個直譯器元件,可以實現 JAVA 位元組碼和計算機作業系統之間的通訊,java程式只需要在JVM 上一次編譯,多出執行,因此JAVA具有跨平臺性。

記憶體結構

  • 方法區(常量池、靜態變數、建構函式、類資料)
  • 堆(物件、類例項、GC的主要區域)
    • 新生區(Minor GC 、Full GC清理無用資料)
      • 伊甸園(物件建立)
      • 倖存 0 區
      • 倖存 1 區
    • 老年代(物件的宣告週期到老年代結束)(Full GC)
    • 永久區(jdk 1.8 以後被元空間代替)(Major GC)
  • 程式計數器(記錄每個執行執行緒的記憶體地址)
  • 虛擬機器棧(每個方法建立都會建立一個棧,棧內的資料都是臨時的)
  • 本地方法棧
  • 直接記憶體

堆中的 GC 回收過程

物件會在 Eden(伊甸園)分配建立,當 Eden(伊甸園)沒有足夠空間時將發起一次 Minor GC(垃圾清理),當 Eden 執行 Minor GC 後還不足以為物件分配空間,則大的物件直接進入老年代,可以用引數設定大物件直接進入老年代,避免頻繁 Minor GC 。如果物件在 Eden 建立,發生 Minor GC 後仍然存活,且能被 Survivor 倖存去容納,年齡加 1, 達到一定年齡進入老年代,預設為 15。發生 Mrinor GC之前先檢查老年代最大可用連續空間是否大於新生代所有物件總空間,如果大於,說明 Minor GC 安全;否則會判斷是否被擔保失敗,如果擔保失敗了,判斷老年代最大連續空間是否大於歷次晉升到老年代物件的平均大小,如果大於則嘗試 Minor GC ,否則就執行 Full GC 進行物件回收,如果 Full GC 執行完畢後,物件仍然無法被建立,則直接丟擲記憶體溢位的異常(java.lang.OutOfMemoryError)。

如何改變物件物件進入老年代的最大值?

通過修改-XX:PretenureSizeThreshold引數來設定進入老年代的物件年齡。這樣也避免在 Eden(伊甸園)區和兩個 Survivor 之間發生大量的記憶體複製。(預設值為 15)

GC如何判斷物件是否改被回收

垃圾收集的演算法

都有那些垃圾回收器

記憶體洩漏(不再使用的物件的記憶體不能被GC回收)

記憶體洩漏的例子:

單例模式:

不正確使用單例模式是引起記憶體洩漏的一個常見問題,單例物件在初始化後將在JVM的整個生命週期中存在(以靜態變數的方式)。如果單例物件持有外部的引用,那麼這個物件將不能被JVM正常回收,導致記憶體洩漏。所以需要注意,儘量不要在單例中持有大物件。

各種連線:

比如資料庫連線、socket連線、檔案流等,除非其顯式的呼叫其close()方法將連線關閉,否則是不會自動被垃圾 回收的。

靜態集合類:

我們迴圈申請Object物件,並將所申請的物件放入一個Vector中。如果我們僅僅釋放引用本身,那麼Vector仍然引用該物件,所以這個物件對GC來說是不可回收的。

如果物件加入到Vector後,還必須從Vector中刪除,最簡單的方法就是將Vector物件設定為null。

Static Vector v = new Vector(10); for (int i = 0; i < 100; i++) {     Object o = new Object();     v.add(o);     o = null; }
事件監聽器:

AWT的事件處理機制是一種委派式事件處理方式:普通元件(事件源)將整個事件處理委託給特定的物件(事件監聽器);當該事件源發生指定的事件時,就通知所委託的事件監聽器,由事件監聽器來處理這個事件。

比如常用的監聽器有ActionListener、KeyListener、MouseListener、MouseMotionListener(專門處理滑鼠運動事件的,比如滑鼠的移動和拖動)

如果在釋放物件的時候沒有記得刪除這些監聽器,會增加記憶體洩露的機會。

 import java.awt.*; import java.awt.event.*; public class TestButton { public static void main(String args[]) {     Frame f = new Frame("Test");     Button b = new Button("Press Me!");     b.addActionListener(new ButtonHandler()); /*註冊事件監聽器*/     f.setLayout(new FlowLayout()); //設定佈局管理器     f.add(b);     f.setSize(200,100);     f.setVisible(true); } } //實現介面ActionListener才能做事件ActionEvent的處理者 class ButtonHandler implements ActionListener {    public void actionPerformed(ActionEvent e)   {      System.out.println("Action occurred");   } }

調優

JVM 思維導圖

最後

這些JVM篇章已經全部整理成一套完整且體系的pdf文件,無論是思維腦圖、學習筆記還是面試考點全整理好了,實際內容還有很多,就不一一展示,若你也需要這一套學習資料。
關注我的公眾號:前程有光即可領取

相關文章