1. 程式人生 > 實用技巧 >Java 記憶體管理視覺化

Java 記憶體管理視覺化

>>> hot3.png

開源專案:https://github.com/kittylyst/jfx-mem 提供給我們一個Java記憶體分配和GC的視覺化過程。

執行方法:

下載程式碼到本地,使用IDEA開啟工程,新建配置,選擇“Application”。

區塊解釋:

eden區使用者新分配記憶體區,也是使用最為頻繁的區域,一般執行緒的TLAB(Thread Local Allocation Buffer)都是在eden去開闢,且執行緒間隔離。eden區 、survivor區、old區的記憶體之和為Heap區,其中eden區與servivor為Young Gen(新生代)。當eden區滿後會觸發一次YGC,eden區中還需要被使用的物件會被移到survivor區中(survivor一般為2個,也成為from區、to區),這樣整個Eden區都是未被使用的空間,可共繼續建立物件,當Eden區再次用完,再觸發一次Yong GC,將Eden區和From區還在被使用的物件複製到To區,下一次Yong GC則是將Eden區和To區的還被使用的物件複製到From區。因此,進過多次Yong GC,某些物件會在From區和To區多次複製,如果超過某個閥值物件還未被釋放,則將該物件複製到Old Generation。如果Old Generation空間也用完,那麼就會觸發一次Full GC,即所謂的全量回收,全量回收會對系統性能產生較大影響,因此應根據系統業務特點和物件週期,合理設定Yong Generation 和 Old Generation大小,儘量減少 Full GC。為什麼Full GC會對系統性能產生較大影響,原因是Full GC不可避免的需要“stop the world” 讓應用程式的所有經常暫停。

執行過程:

從動畫中我們還可以看出,Old區採用的跟蹤計數器(相對於引用計數器)的演算法是:標記-清除-壓縮 的方式,那我們常用的跟蹤計數器的演算法有那些呢,各有什麼優缺點? 常見的垃圾回收方法有: 1. 複製; 從根集合搜掃描出存活的物件,然後將存活的物件複製到一塊新的未使用的空間中,當要回收的空間中存活的物件較少時,比較高效; 2. 標記-清除; 從根集合開始掃描,對存活的物件進行標記,比較完畢後,再掃描整個空間中未標記的物件,然後進行回收,不需要對物件進行移動;弊端是造成記憶體碎片,可能記憶體有500M,當需要100M時就沒有記憶體了,需要觸發一次FGC。 3. 標記-壓縮; 標記形式和“標記清除”一樣,但是回收不存活的物件後,會把所有存活的物件在記憶體空間中進行移動,好處是減少了記憶體碎片,缺點是成本比較高; 新時代中物件存活時間比較短,YGC次數也比較多,故可以採用效率比較高的複製策略,YGC觸發時,把Eden區和From區還存在應用關係的複製到To區中,下一次是把Eden區和To區複製到From區。 新時代可用的GC方法和老年代可用的GC方法是不一樣的: 新時代可用GC方法:序列GC(Serial GC)、並行回收GC(Parallel Scavenge)、併發GC(ParNew) 老年代可用GC方法:序列GC(Serial MSC)、並行GC(Parallel MSC)、併發GC(CMS) GC 的組合型別(每個引數型別都對應了YGC、FGC採用的GC策略):
引數 描述
UseSerialGC 虛擬機器執行在Client模式的預設值,開啟此開關引數後,使用Serial+Serial Old收集器組合進行垃圾收集。
UseParNewGC 開啟此開關引數後,使用ParNew+Serial Old收集器組合進行垃圾收集。
UseConcMarkSweepGC 開啟此開關引數後,使用ParNew+CMS+Serial Old收集器組合進行垃圾收集。Serial Old作為CMS收集器出現Concurrent Mode Failure的備用垃圾收集器。
UseParallelGC 虛擬機器執行在Server模式的預設值,開啟此開關引數後,使用Parallel Scavenge+Serial Old收集器組合進行垃圾收集。
UseParallelOldGC 開啟此開關引數後,使用Parallel Scavenge+Parallel Old收集器組合進行垃圾收集。
檢視我們小二後臺的jvm引數設定,我們使用的是CMS方式: -XX:+UseConcMarkSweepGC 表示使用CMS策略;CMS策略預設只做標記-清除,並不做壓縮,如果期望FGC的時候,同時做壓縮,解決記憶體碎片的問題,可以採用的方式是新增引數:-XX:+UseCMSCompactAtFullCollection; -XX:CMSInitiatingOccupancyFraction=80 表示只有在第一次Old區使用率超過80%時,自動觸發CMS GC,後面都是使用HotSpot VM自動計算出來的值。 -XX:+UseCMSInitiatingOccupancyOnly 表示命令JVM不基於執行時收集的資料來啟動CMS垃圾收集週期。而是,當該標誌被開啟時,JVM通過CMSInitiatingOccupancyFraction的值進行每一次CMS收集,而不僅僅是第一次。 -XX:+CMSClassUnloadingEnabled相對於並行收集器,CMS收集器預設不會對永久代進行垃圾回收。如果希望對永久代進行垃圾回收,可用設定標誌-XX:+CMSClassUnloadingEnabled。在早期JVM版本中,要求設定額外的標誌-XX:+CMSPermGenSweepingEnabled。注意,即使沒有設定這個標誌,一旦永久代耗盡空間也會嘗試進行垃圾回收,但是收集不會是並行的,而再一次進行Full GC。 如果想更深入瞭解CMS收集器的原理,可以參考: http://ifeve.com/useful-jvm-flags-part-7-cms-collector/ 從上圖中可以看出,Old區滿了,即將做一次FGC,如果FGC後記憶體還是滿了,就會觸發OutOfMemory。

轉載於:https://my.oschina.net/boltwu/blog/416417