本文目錄
- JVM 記憶體結構
- JVM 常見引數
- GC 演算法
- 物件存活判斷
- 垃圾回識訓制
- 垃圾收集演算法
- 垃圾收集程序
- 垃圾收集器 Garbage Collector
- Java 記憶體模型
- Java 物件模型
- JVM 性能監控與故障處理工具
- JDK 的可視化工具
JVM 記憶體結構
虛擬機在執行 Java 程式的程序中會把所管理的記憶體劃分為若干個不同的資料區域:

-
方法區與堆一樣,是各個執行緒共享的記憶體區域,用于存盤已被虛擬機加載的類資訊、常量、靜態變數、即時編譯器編譯后的代碼等資料.
HotSpot虛擬機把方法區叫做永久代(Permanent Generation)- 在 jdk1.7 中,符號參考放到 native heap,字串常量、類的靜態變數放到 java heap
- 在 jdk1.8 中,永久代被移除,類的元資料放到本地堆記憶體(
native heap)中,這一塊區域叫Metaspace(元空間)
-
運行時常量池:方法區的一部分,用于存放編譯器生成的各種字面量和符號參考,這部分內容將在類加載后存放到方法區的運行時常量池中
-
堆:被所有執行緒共享的一塊記憶體區域,在虛擬機啟動時創建,所有的物件實體以及陣列都要在堆上分配記憶體
- 使用
new關鍵字,就表示在堆中開辟一塊新的存盤空間 - 堆記憶體由年輕代/新生代和老年代組成,而年輕代又被分成三部分,
Eden 空間、From Survivor 空間、To Survivor 空間,默認情況下年輕代按照 8:1:1 的比例來分配 - 堆記憶體又被劃分成不同的部分:伊甸區(
Eden)、幸存者區域(Survivor Sapce)、老年代(Old Generation Space)
- 使用
-
Java 虛擬機堆疊:每個執行緒在創建時都會創建一個虛擬機堆疊,其內部保存一個個的堆疊幀,每個方法被執行時都會同時創建一個堆疊幀用于存盤
區域變數表、操作堆疊、動態鏈接、方法出口等資訊,當方法呼叫完畢,該方法的堆疊幀就被銷毀了 -
本地方法堆疊:每個執行緒在呼叫本地方法時都會創建一個堆疊幀,為虛擬機使用到的
native方法服務 -
程式計數器:每個執行緒都有自己的程式計數器,用來記錄當前執行緒正在執行的位元組碼指令的地址

JVM 常見引數

- –Xms 設定堆的最小空間大小,默認為物理記憶體的 1/64
- –Xmx 設定堆的最大空間大小,默認為物理記憶體的 1/4
- –Xss 設定每個執行緒的堆疊大小,jdk1.5 以后默認為 1M
- –Xdebug 在除錯模式下運行
- –XX:NewSize 設定新生代最小空間大小
- –XX:MaxNewSize 設定新生代最大空間大小
- –XX:PermSize 設定永久代最小空間大小
- –XX:MaxPermSize 設定永久代最大空間大小
- –XX:NewRatio 設定老年代與新生代的比值,默認值為 3
- –XX:SurvivorRatio 設定年輕代中 Eden 區與 2 個 Survivor 區的比值
- –XX:MaxTenuringThreshold 表示一個物件如果在 Survivor 區移動的次數達到設定值還沒有被垃圾回收就進入老年代(如果設定為 0 的話,則年輕代物件不經過 Survivor 區,直接進入老年代)
- –XX:PretenureSizeThreshold 直接晉升到老年代的物件大小
- –XX:+PrintGCDetails 輸出詳細的 GC 處理日志
- –XX:+HeapDumpOnOutOfMemoryError 讓 JVM 碰到 OOM 場景時輸出 dump 資訊
注意:命令的X前面是兩個 - 哦,比如 - - Xms
GC 演算法
物件存活判斷
判斷物件是否存活一般有兩種方式:
- 參考計數:每個物件有一個參考計數屬性,新增一個參考時計數加 1,參考釋放時計數減 1,計數為 0 時可以回收(
Java 并沒有選擇參考計數,因為存在物件相互回圈參考的問題),像python這種腳本語言是用的參考計數法 - 可達性分析(
Reachability Analysis):從GC Roots開始向下搜索,搜索所走過的路徑稱為參考鏈,當一個物件到GC Roots沒有任何參考鏈相連時,則認為此物件是不可達的(JVM 會把虛擬機堆疊和本地方法堆疊中正在參考的物件、靜態屬性參考的物件和常量,作為 GC Roots)
垃圾回識訓制
- 自動垃圾回識訓制;只能回收堆記憶體中不再被程式參考的物件所占的記憶體
- 回收內容:堆中的可回收物件;方法區無用的元資料(
卸載不再使用的型別,默認 -XX:+ClassUnloadingWithConcurrentMark)
垃圾收集演算法
- 垃圾收集演算法主要有:復制、標記-清除、標記-整理
- 復制演算法(
Copying)- 將記憶體分為大小相等的兩塊,每次只用其中一塊,一塊記憶體用完之后,將存活物件復制到另一塊記憶體區域,然后將原來的半塊記憶體區城全部回收
- 只需移動堆頂指標,按順序分配記憶體即可,實作簡單,運行高效,
且記憶體回收后不會產生記憶體碎片 - 缺點:可用記憶體縮小為原來的一半,代價高
- 標記-清除演算法(
Mark-Sweep)- 首先標記出所有需要回收的物件,然后進行清除
- 缺點:標記和清除程序的效率都不高;記憶體回收后會產生大量不連續的記憶體碎片
- 標記-整理演算法(
Mark-Compact)- 標記需要回收的物件,將存活物件移動到一端,然后將端邊界以外的記憶體回收
- 分代收集演算法(
Generational Collection)- GC 分代的基本假設:絕大部分物件的生命周期都非常短暫,存活時間短
- 把 Java 堆分為新生代和老年代,根據各個年代的特點采用最適當的收集演算法
- 在新生代中,每次垃圾收集時都發現有大批物件死去,只有
少量存活,選用復制演算法,只需要付出少量存活物件的復制成本就可以完成收集;而老年代中因為物件存活率高、沒有額外空間對它進行分配擔保,必須使用“標記-清理”或“標記-整理”演算法來進行回收
垃圾收集程序
- 當 Eden 區的空間占用達到一定閾值時,觸發
Minor GCEden區中所有存活的物件都會被復制到 To 區域,而在 From 區中仍存活的物件會根據它們的年齡值來決定去向,年齡達到一定值(年齡閾值)的物件會被移動到老年代中,沒有達到閾值的物件會被復制到 To 區域 - 當老年代的剩余空間不足的時,觸發
Major GC - 老年代 GC 叫作
Major GC,將對整個堆進行的清理叫作Full GC
垃圾收集器 Garbage Collector
-
Serial 收集器:一個采用單個執行緒并基于復制演算法作業在新生代的收集器,進行垃圾收集時,必須暫停其它所有的作業執行緒(
Stop The World),是 Client 模式下 JVM 的默認選項,-XX:+UseSerialGC -
Serial Old 收集器:一個采用單執行緒基于標記-整理演算法并作業在老年代的收集器
-
ParNew 收集器:Serial 收集器的多執行緒版本(使用多個執行緒進行垃圾收集),
-XX:+UseParNewGC -
CMS 收集器(
Concurrent Mark Sweep):一種以盡量減少停頓時間為目標的收集器,作業在老年代,基于標記-清除演算法實作,-XX:+UseConcMarkSweepGC -
Parallel Scavenge 收集器:一個采用多執行緒基于復制演算法并作業在新生代的收集器,也被稱作是吞吐量優先的 GC,是早期 jdk1.8 等版本中 Server 模式 JVM 的默認 GC 選擇,
-XX:+UseParallelGC,使用Parallel Scavenge(年輕代)+Serial Old(老年代)的組合進行 GC -
Parallel Old 收集器:一個采用多執行緒基于標記-整理演算法并作業在老年代的收集器,適用于注重于吞吐量及 CPU 資源敏感的場合,
-XX:+UseParallelOldGC,使用Parallel Scavenge(年輕代)+Parallel Old(老年代)的組合進行 GC -
G1 收集器:jdk1.7 提供的一個作業在新生代和老年代的收集器,基于標記-整理演算法實作,在收集結束后可以避免記憶體碎片問題,一種兼顧吞吐量和停頓時間的 GC,是
Oracle jdk1.9以后的默認 GC 選項

-
jdk1.7 默認垃圾收集器
Parallel Scavenge(新生代)+ Serial Old(老年代) -
jdk1.8 默認垃圾收集器
Parallel Scavenge(新生代)+ Serial Old(老年代) -
jdk1.9 默認垃圾收集器
G1
-XX:+PrintCommandLineFlags查看 JVM 設定的 XX 選項的值
-XX:+PrintGCDetails查看 GC 日志的新生代、老年代名稱判斷
Java 記憶體模型
Java 記憶體模型(Java Memory Model,JMM)是一個抽象的概念,描述了一組規則或規范,定義了程式中各個共享變數的訪問規則

- JMM 規定了所有的變數都存盤在主記憶體(
Main Memory)中 - 每個執行緒還有自己的作業記憶體(
Working Memory),執行緒的作業記憶體中保存了該執行緒使用到的變數的主記憶體的副本拷貝,執行緒對變數的所有操作(讀取、賦值等)都必須在作業記憶體中進行,而不能直接讀寫主記憶體中的變數(volatile 變數仍然有作業記憶體的拷貝,但是由于它特殊的操作順序性規定,所以看起來如同直接在主記憶體中讀寫訪問一般) - 不同的執行緒之間也無法直接訪問對方作業記憶體中的變數,執行緒之間值的傳遞都需要通過主記憶體來完成
Java 物件模型
-
Java 物件在 JVM 中的存盤結構
-
HotSpot 虛擬機中,設計了一個
OOP-Klass Model,OOP(Ordinary Object Pointer)指的是普通物件指標,而 Klass 用來描述物件實體的具體型別 -
每一個 Java 類,在被 JVM 加載的時候,JVM 會給這個類創建一個
instanceKlass,保存在方法區,用來在 JVM 層表示該 Java 類,當我們在 Java 代碼中,使用 new 創建一個物件的時候,JVM 會創建一個instanceOopDesc物件,這個物件中包含了物件頭以及實體資料
JVM 性能監控與故障處理工具
- jps:
JVM Process Status Tool,顯示指定系統內所有的 HotSpot 虛擬機行程 - jcmd:發送診斷命令請求到正在運行的 JVM
- jstat:
JVM Statistics Monitoring Tool,用于收集 HotSpot 虛擬機各方面的運行資料 - jstack:
Stack Trace for Java,顯示虛擬機的執行緒快照 - jinfo:
Configuration Info for Java,顯示虛擬機配置資訊 - jmap:
Memory Map for Java,生成虛擬機的記憶體轉儲快照(heapdump 檔案) - jhat:
JVM Heap Dump Browser,用于分析heapdump檔案,它會建立一個 HTTP/HTML 服務器,讓用戶可以在瀏覽器上査看分析結果
JDK 的可視化工具
- JConsole:Java 監視和管理控制臺
- JMC(Java Mission Control)
- Visual VM:多合一故障處理工具
最后,大家記得收藏加關注哦
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/299666.html
標籤:java
