Java之JVM快速入門

JVM探究

  • 請你談談你對JVM的理解,java8虛擬機和之前的變化更新
  • 什麼是OOM,什麼是棧溢出StackOverFlowError?怎麼分析
  • JVM的常用調優參數有哪些
  • 內存快照如何抓取,怎麼分析Dump文件
  • 談談JVM中,類加載器的認識 rt-jar ext application

JVM的位置

JVM位置

JVM的體系結構

體系結構

類加載器及雙親委派機制

類加載器作用:加載Class文件 new Student();
類加載器
1.虛擬機自帶的加載器
2.啓動類(根)加載器
3.擴展類加載器 /jre/lib/ext
4.應用程序(系統類)加載器 rt.jar

雙親委派機制
雙親委派機制
委派機制的作用:

  • 防止重複加載同一個.class。通過委託去向上面問一問,加載過了,就不用再加載一遍。保證數據安全。
  • 保證核心.class不能被篡改。通過委託方式,不會去篡改核心.class,即使篡改也不會去加載,即使加載也不會是同一個.class對象了。不同的加載器加載同一個.class也不是同一個Class對象。這樣保證了Class執行安全。

Native

凡是帶native關鍵字的,調用底層C的庫,會進入本地方法棧,調用本地方法接口(JNI java native interface)
JNI的作用:擴展Java的使用,融合不同的編程語言爲Java所用
Java在內存區域中開闢了一塊標記區域,即本地方法棧,登記native方法,在最終執行的時候加載本地方法庫中的方法

方法區:
方法區是被所有線程共享,所有字段和方法字節碼,以及一些特殊方法如構造函數、接口代碼也在此定義,簡單說,所有定義的方法的信息都保存在該區域,此區域屬於共享區間
靜態變量、常量、類信息(構造方法 接口定義)、運行時的常量池存在方法區中
方法區:static final Class模版 常量池

但實例變量存在對內存中,和方法區無關

棧:主管程序的運行,生命週期和線程同步;線程結束,棧內存也就釋放,對於棧來說,不存在垃圾回收問題
棧:8大基本類型 對象的引用 實例的方法

一個JVM只有一個堆內存,堆內存的大小是可以調節的
類加載器讀取了類文件後,一般會把類的實例 方法 常量 變量放到堆,保存我們所有引用類型的真實對象
堆內存中還要細分爲三個區域:

  • 新生區
  • 老年代
  • 永久區
    JDK8之前的堆
    GC垃圾回收主要在伊甸園區和養老區
    JDK8之後,永久區修改爲元空間
    JDK8之後
    新生區
  • 類:誕生和成長的地方,甚至死亡
  • 伊甸園:所有的對象都是在伊甸園new
  • 倖存區(0區 1區)
    永久區
    這個區域常駐內存
  • JDK6 永久代,常量池在方法區
  • JDK7 永久代,但是慢慢退化了,去永久代,常量池在堆中
  • JDK8之後,無永久代,常量池在元空間
    在這裏插入圖片描述
    JDK1.8堆
    在這裏插入圖片描述
    在這裏插入圖片描述
public class Demo01 {
    public static void main(String[] args) {
        long maxMemory = Runtime.getRuntime().maxMemory();
        long totalMemory = Runtime.getRuntime().totalMemory();

        System.out.println("max:" + (maxMemory/(double)1024/1024));
        System.out.println("total:" + (totalMemory/(double)1024/1024));
    }
}

//最大分配內存 maxMemory是機器內存的1/4
//初始化內存 totalMemory是maxMemory的1/16

OOM:

  • 嘗試擴大堆內存看結果 -Xms1024m(totalMemory) -Xmx1024m(maxMemory) -XX:+PrintGCDetails
  • 分析內存,看哪個地方出現問題
max:3641.0
total:245.5
Heap
 PSYoungGen(年輕代)      total 76288K, used 3932K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space(伊甸園) 65536K, 6% used [0x000000076ab00000,0x000000076aed7240,0x000000076eb00000)
  from space(倖存區) 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
  to   space(倖存區) 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
 ParOldGen(老年代)       total 175104K, used 0K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0000000,0x00000006cab00000)
 Metaspace(元空間)       used 2889K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 313K, capacity 388K, committed 512K, reserved 1048576K

元空間邏輯上存在,物理不存在 年輕代76288K+老年代175104K=total245.5M

public class Demo02 {
    public static void main(String[] args) {
        String str = "test";
        while (true) {
            str = str + new Random().nextInt(88888888) + new Random().nextInt(99999999);
        }
    }
}
[GC (Allocation Failure) [PSYoungGen: 940K->128K(1024K)] 956K->497K(1536K), 0.0041953 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 418K->415K(1024K)] [ParOldGen: 418K->418K(512K)] 837K->834K(1536K), [Metaspace: 3600K->3600K(1056768K)], 0.0068552 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 415K->415K(1024K)] [ParOldGen: 418K->418K(512K)] 834K->834K(1536K), [Metaspace: 3600K->3600K(1056768K)], 0.0062713 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3332)
	at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:674)
	at java.lang.StringBuilder.append(StringBuilder.java:208)
	at com.wang.Demo02.main(Demo02.java:14)

OOM排障:eclipse MAT,idea Jprofiler

  • 分析Dump內存文件,快速定位內存泄漏
  • 獲得堆中的數據
  • 獲得大的對象

-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
在Jprofiler查看BigObject

JVM在進行GC時,並不是對這三個區域統一回收,大部分時候,回收的是新生代

  • 新生代
  • 倖存區 0區1區 from to
  • 老年代

GC:兩種類型

  • 輕GC 新生代&倖存區
  • full GC 三個區域

GC的算法:標記清除法 標記整理(壓縮)法 複製算法 引用計數法

引用計數法:
引用計數法
複製算法:
每次GC都會將伊甸園區活得對象移到倖存區中,一旦伊甸園區被GC後就會是空的
倖存區0和倖存區1 一個是from 一個是to 誰空誰是to,當兩個倖存區都不是空的時候複製算法把其中一個區的對象複製到另一個區,形成一個空區
當一個對象經歷了15次GC還沒有被回收,進入老年代 -XX:MaxTenuringThreshold

年輕代主要使用的是複製算法(伊甸園 倖存0 倖存1)

  • 好處 沒有內存碎片
  • 壞處 浪費了內存空間(一個倖存區)
    複製算法最佳使用場景:對象存活度較低

標記清除算法:
在這裏插入圖片描述

  • 優點:不需要額外的空間
  • 缺點:兩次掃描浪費時間,會產生內存碎片
    在這裏插入圖片描述

總結:
內存效率(時間複雜度):複製算法>標記清除算法>標記壓縮算法
內存整齊度:複製算法=標記壓縮算法>標記清除算法
內存利用率:標記清除算法=標記清除算法>複製算法

GC:採用分代收集算法
即,年輕代使用複製算法,因爲存活率低;老年代區域大,存活率高,使用標記清除+壓縮算法,多次清除形成大量內存碎片之後執行一次壓縮

JMM

JMM(Java Memory Model的縮寫)允許編譯器和緩存以數據在處理器特定的緩存(或寄存器)和主存之間移動的次序擁有重要的特權,除非程序員使用了volatile或synchronized明確請求了某些可見性的保證。

JMM是幹嘛的?作用:緩存一致性協議,用於定義數據讀寫的規則
JMM定義了線程工作內存和主內存之間的抽象關係,線程之間的共享變量存儲在主內存中,每個線程都有一個私有的本地內存
在這裏插入圖片描述
解決共享對象可見行的問題:volilate

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