JVM內存管理概述
JVM提供自動內存管理功能,以免編程人員手動管理內存。新對象分配在堆內存上。甲根集由指針外部存儲器,靜態變量,線程,JNI引用和內部JVM結構。從根集直接訪問的對象必須保存在堆中。從任何可訪問對象可訪問的對象也必須位於堆中。這組對象是唯一可以被程序使用的對象。使用稱為垃圾回收(GC)的進程刪除不可訪問的對象(垃圾)。可達對象被壓縮,即移動到堆中的連續空間。這很重要,否則堆會變得分散。
熱點中的代GC和內存空間
當JVM啟動時,它從操作系統請求一些內存。這個內存被分成各種空間。
JDK 8之前的JVM中的內存空間
獨立的泳池擁有不同年齡段的物體
JVM的GC是世代的,並基於以下假設:
大多數物體都會死亡
很少有參考從較舊的對年輕的對象
有兩代物體:
年輕:小而經常收集(小收集)。在閾值數量的GC中存活的物體轉移到老一代。
舊:大,很少收集(主要收集=完整的GC)
在JDK 8之前,還有一個永久代,用於存儲類表示和元數據,實例化字符串和類靜態。這在JDK 8和更高版本中被元空間所取代。
元空間分配在本機內存中。它通過JVM選項MetaspaceSize進行管理,初始大小為MaxMetaspaceSize,最大值為MaxMetaspaceSize。
如果啟用UseCompressedClassPointers,則會使用2個內存區域來存儲類及其元數據 - 元空間和壓縮類空間。用32位偏移量表示的64位類指針可節省空間。類元數據由存儲在壓縮類空間中的32位偏移量引用。默認情況下,壓縮類空間為1 GB。
代碼緩存用於存儲由JIT(即時優化器)生成的編譯代碼,由本機內存分配並由Code Cache Sweeper管理
熱點JVM中的垃圾收集器
JVM針對不同代的對象有不同的垃圾收集方法。其中一些描述如下:
年輕一代收集
串行 - 停止世界(STW),複製收集器,單線程
ParNew - STW,複製收集器,多個GC線程
並行清除 - STW,複製收集器,多個GC線程
老一代收集
串行舊 - STW,標記掃描 - 緊湊型收集器,單線程
內容管理系統 - 大部分是併發的,低暫停
並行舊壓縮採集器,多個GC線程
G1:專為大堆設計,並提供可預測的短暫停頓。
幾代人都有不同的內存佈局
所有世代相同的收藏家
JDK的GC選項
這些是傳遞給JVM的選項標誌,用於指定要使用的GC:
UseSerialGC:Serial + SerialOld
-
UseParNewGC:ParNew + SerialOld。在JDK 9中,將舊CMS用於CMS
UseConcMarkSweepGC:ParNew + CMS + SerialOld
沒有堆壓實會導致碎片化。有浮動垃圾並需要更大的堆大小。
可用空間維護為鏈接列表。與凹凸指針分配相比,分配開銷較大。
額外的年輕收藏費用
CMS使用大部分時間收集老一代。在發生併發模式故障時使用SerialOld。
CMS與應用程序線程同時執行大部分工作。
在JDK 9中棄用
UseParallelGC:並行清除+並行舊。
最大化吞吐量。
默認GC直到JDK 9
兩代使用G1GC-G1
針對具有大內存的多核機器的服務器樣式GC
低GC在嘗試高吞吐量時以高概率暫停
壓實收集器。低停頓沒有碎片
更好的GC人體工程學。並行線程和一些任務與應用程序線程併發
從JDK 7u4開始可用,在JDK 9中默認使用
有關調整垃圾回收器的更多詳細信息,請閱讀官方的GC調整指南
未成年人或年輕一代是如何收集的:
當年輕的伊甸園空間已滿時,可到達的對象被標記並移動到ToSurvivorSpace
可以訪問FromSurvivor空間中的對象將移至ToSurvivorSpace
已經越過閾值的FromSurvivor空間中的對象被提升為舊一代
伊甸園變得空無一人,為新的分配做好準備
往返於倖存者空間切換
關於Mark-Sweep-Compact收集器的注意事項(Serial Old):
標記階段:標記所有活物
-
掃描階段:掃過堆確定垃圾
滑動階段:GC通過將活動對象滑動到堆的開始位置來執行滑動壓實
閱讀更多 高效碼農 的文章