本章主要介紹瞭如何使用G1垃圾收集器以及如何將其與Hotspot JVM一起使用的基礎知識。
在介紹這個技術之前先給大家簡單講一些基本簡單詞彙方便大家理解:
名詞 | 描述 |
---|---|
JIT Compiler | just-in-time 編譯器在程序啓動後運行,然後將代碼(通常是字節碼或某種VM指令)即時(或稱爲即時)編譯爲通常更快的形式 |
CMS | 併發標記掃描 |
STW | (Stop the World ) 暫停JVM |
G1 | Garbage-First 回收器 |
Java虛擬機
我們這邊衆所周知 Java是一種面向對象的編程語言,
它具有平臺獨立性-Java應用程序被編譯爲字節碼,該字節碼存儲在類文件中並加載到JVM中。java的相關應用在JVM中運行,因此它們可以在許多不同的操作系統和設備上運行。
JVM 結構
JVM的主要組件包括類加載器,運行時數據區域和執行引擎。
但是跟性能相關的組件如圖:
JVM的三個組件主要在調整性能時着重。該堆是你的對象數據的存儲位置。然後,該區域由啓動時選擇的垃圾收集器管理。大多數調整選項都與確定堆大小和實際情況選擇最合適的垃圾收集器有關。JIT complier 對性能也有很大的影響。
JVM調試目標
在大型壓力環境或者高併發場景的時候,通常我們調試Java 應用程序的過程中,通常會將目標放在兩個點:
- System Responsiveness [響應能力]
- System Throughput[吞吐量]
[響應能力]
主要體現 三個方面:
- 用戶操作瀏覽器請求網站返回頁面的速度
- 處理事件的響應速度
- 數據庫查詢返回的速度
對於注重響應性的應用程序,例如 支付、登錄、IM等大流量型系統 較長的STW 時間是不可接受的。需要系統在短時間內做出積極響應。
[吞吐量]
吞吐量專注於最大程度地提高應用程序在特定時間段內的工作量。如何測量吞吐量的示例包括:
- 特定時間內完成的事務數。
- 批處理程序在單位時間內可以完成的event數量。
- 單位時間內對DataBase進行查詢完成數據數量集
高暫停時間對於注重吞吐量的應用程序是可以接受的。由於高吞吐量應用程序會在更長的時間內關注基準測試,因此不考慮快速響應時間。
G1垃圾收集器
垃圾優先(G1)收集器是服務器樣式的垃圾收集器,目標是具有大內存的多處理器計算機。它極有可能滿足垃圾回收(GC)暫停時間目標,同時實現高吞吐量。G1收集器設計用於以下應用程序 目的 是 【Oracle 官網給的結論】
我這邊翻譯了一下我這邊理解 大概意思應該是:G1 其目的是
壓縮自由的空間,減少GC引起的STW時間
增加調試的便捷性,預測更多的GC暫停時間
傳統的JVM 結構(java7 與 java 8比對)
大家對比兩個圖發現了
二者 從java7---->java8 JVM結構是發生了變化
Oracle完全擺脫了“ PermGen【永久代】”,並用Metaspace【元空間】代替了它。
什麼是PermGen?
PermGen是Permanent Generation的縮寫,是Heap中的內存區域,JVM使用它來存儲類和方法對象。java的應用程序加載了很多類,那麼PermGen的利用率將會很高。
對於大多數應用程序,-XX:MaxPermSize=256MB 應該夠了
如果大家帶開發代碼的過程中遇到這個錯誤:
“ java.lang.OutOfMemoryError:PermGen space ”
那就是這個參數導致的。
PermGen和Metaspace區別:
如圖可以看出來java7 版本 PermGen是Java Heap的一部分(通過-Xmx選項配置的最大大小),到java8 的時候Metaspace不是Heap的一部分。而是元空間是本機內存(進程內存)的一部分,而本機內存僅受主機操作系統的限制,類元數據分配受可用本機內存量限制(容量將取決於否使用32位JVM與64位以及操作系統虛擬內存的可用性)。
Metaspace介紹
元空間容量
- 可以通過-xx:MaxMetaspaceSize 設置允許限制用於類元數據的本機內存量。如果不指定此標誌,則Metaspace將在運行時根據應用程序需求動態調整大小。
元空間垃圾收集
- 如果類元數據使用量 達到了“ MaxMetaspaceSize”極限值,就會觸發過期類和類加載器的垃圾收集。
那看到這裏很多朋友會問,那其實也對程序也沒有什麼影響對吧?
我來解釋一下,這個變化意義在哪裏呢?
個人理解就是你這邊在開發應用程序的時候,如果應用程序加載了高負荷類(和/或內部字符串)如果導致元工空間不足的話,可能操作系統關閉。後續對於gc系統監控有一定的便捷。
除此之外撤銷的永久代,增大了Heap 堆的使用率。爲新生代舊生代提供更多的空間。
CMS回收
CMS回收是在舊生代上完成.
主要步驟:
1. Initial Mark (STW)
掃描老一代集合對象中可訪問的被“標記”的對象,包括那些年輕一代可能可以訪問的對象。此時標記過程比較短暫 暫停時間通常持續時間較短。
2. Concurrent Marking [併發標記]
第一次標記完成,此時恢復當前暫停運行的線程,併發對第一次已經標記的對象進行循環深度標記[標記已經標記的對象可訪問的對象] 需要注意 併發標記同時可能會出現Minor GC [新生代GC]同時發生,那麼對應舊生代引用關係會重新改變。同時就就產生浮動垃圾【原本被引用的數據因爲其他對象引用狀態改變,導致不在引用】
3. Final Marking (remark)[再次標記 STW]
重新掃描,會暫停運行線程,針對Concurrent Marking 步驟過程出現的對象的更新而導致併發標記階段遺漏的對象( 關係修改的對象以及新創建對象)進行重新標記 。
4. Concurrent Sweep [併發收集]
恢復線程,針對標記階段被標識爲不可訪問的對象進行回收。死對象的集合將對象的空間添加到空閒列表中,以供以後分配。
5. Resetting 重置
通過清除數據結構爲下一個併發收集做準備。
CMS Collector
年輕代 : Eden + 2個生存區
年老代: 連續的內存空間
Young GC流程
運行一段時間後 大概堆的情況是這個樣子
圖是按順序執行的
Old GC流程
CMS收集器將進入重置階段,並等待下一次達到GC閾值。
相關資料圖片參考oracle官方地址:
有興趣小夥伴可以相互學習討論
https://www.oracle.com/technetwork/tutorials/tutorials1876574.html