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

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文檔,無論是思維腦圖、學習筆記還是面試考點全整理好了,實際內容還有很多,就不一一展示,若你也需要這一套學習資料。
關注我的公眾號:前程有光即可領取