1. 程式人生 > >2021-2-26:為什麼需要 System.gc() ?

2021-2-26:為什麼需要 System.gc() ?

JVM 預設啟動引數中,DisableExplicitGC 為 false,ExplicitGCInvokesConcurrent 為 false,對於大多數 GC (除了 ZGC 的其他 GC,包括 CMS,G1,Shenandoah GC 等等),都是**會進行 FullGC 的**,並且都是**同步 GC 的**,其中底層的原理會在另一篇詳細分析,我們先來搞清楚為什麼要留這樣一個介面呢? # 1. 使用並管理堆外記憶體的框架,需要 Full GC 的機制觸發堆外記憶體回收 JVM 的記憶體,不止堆記憶體,還有其他很多塊,通過 Native Memory Tracking 可以看到: ``` Native Memory Tracking: Total: reserved=6308603KB, committed=4822083KB - Java Heap (reserved=4194304KB, committed=4194304KB) (mmap: reserved=4194304KB, committed=4194304KB) - Class (reserved=1161041KB, committed=126673KB) (classes #21662) ( instance classes #20542, array classes #1120) (malloc=3921KB #64030) (mmap: reserved=1157120KB, committed=122752KB) ( Metadata: ) ( reserved=108544KB, committed=107520KB) ( used=105411KB) ( free=2109KB) ( waste=0KB =0.00%) ( Class space:) ( reserved=1048576KB, committed=15232KB) ( used=13918KB) ( free=1314KB) ( waste=0KB =0.00%) - Thread (reserved=355251KB, committed=86023KB) (thread #673) (stack: reserved=353372KB, committed=84144KB) (malloc=1090KB #4039) (arena=789KB #1344) - Code (reserved=252395KB, committed=69471KB) (malloc=4707KB #17917) (mmap: reserved=247688KB, committed=64764KB) - GC (reserved=199635KB, committed=199635KB) (malloc=11079KB #29639) (mmap: reserved=188556KB, committed=188556KB) - Compiler (reserved=2605KB, committed=2605KB) (malloc=2474KB #2357) (arena=131KB #5) - Internal (reserved=3643KB, committed=3643KB) (malloc=3611KB #8683) (mmap: reserved=32KB, committed=32KB) - Other (reserved=67891KB, committed=67891KB) (malloc=67891KB #2859) - Symbol (reserved=26220KB, committed=26220KB) (malloc=22664KB #292684) (arena=3556KB #1) - Native Memory Tracking (reserved=7616KB, committed=7616KB) (malloc=585KB #8238) (tracking overhead=7031KB) - Arena Chunk (reserved=10911KB, committed=10911KB) (malloc=10911KB) - Tracing (reserved=25937KB, committed=25937KB) (malloc=25937KB #8666) - Logging (reserved=5KB, committed=5KB) (malloc=5KB #196) - Arguments (reserved=18KB, committed=18KB) (malloc=18KB #486) - Module (reserved=532KB, committed=532KB) (malloc=532KB #3579) - Synchronizer (reserved=591KB, committed=591KB) (malloc=591KB #4777) - Safepoint (reserved=8KB, committed=8KB) (mmap: reserved=8KB, committed=8KB) ``` - Java Heap: 堆記憶體,即`-Xmx`限制的最大堆大小的記憶體。 - Class:載入的類與方法資訊,其實就是 metaspace,包含兩部分: 一是 metadata,被`-XX:MaxMetaspaceSize`限制最大大小,另外是 class space,被`-XX:CompressedClassSpaceSize`限制最大大小 - Thread:執行緒與執行緒棧佔用記憶體,每個執行緒棧佔用大小受`-Xss`限制,但是總大小沒有限制。 - Code:JIT 即時編譯後(C1 C2 編譯器優化)的程式碼佔用記憶體,受` -XX:ReservedCodeCacheSize`限制 - GC:垃圾回收佔用記憶體,例如垃圾回收需要的 CardTable,標記數,區域劃分記錄,還有標記 GC Root 等等,都需要記憶體。這個不受限制,一般不會很大的。 - Compiler:C1 C2 編譯器本身的程式碼和標記佔用的記憶體,這個不受限制,一般不會很大的 - Internal:命令列解析,JVMTI 使用的記憶體,這個不受限制,一般不會很大的 - Symbol: 常量池佔用的大小,字串常量池受`-XX:StringTableSize `個數限制,總記憶體大小不受限制 - Native Memory Tracking:記憶體採集本身佔用的記憶體大小,如果沒有打開採集(那就看不到這個了,哈哈),就不會佔用,這個不受限制,一般不會很大的 - Arena Chunk:所有通過 arena 方式分配的記憶體,這個不受限制,一般不會很大的 - Tracing:所有采集佔用的記憶體,如果開啟了 JFR 則主要是 JFR 佔用的記憶體。這個不受限制,一般不會很大的 - Logging,Arguments,Module,Synchronizer,Safepoint,Other,這些一般我們不會關心。 除了 Native Memory Tracking 記錄的記憶體使用,還有兩種記憶體 **Native Memory Tracking 沒有記錄**,那就是: - Direct Buffer:直接記憶體 - MMap Buffer:檔案對映記憶體 針對除了堆記憶體以外,其他的記憶體,有些也是需要 GC 的。例如:MetaSpace,CodeCache,Direct Buffer,MMap Buffer 等等。早期在 Java 8 之前的 JVM,對於這些記憶體回收的機制並不完善,很多情況下都需要 **FullGC** 掃描整個堆才能確定這些區域中哪些記憶體可以回收。 有一些框架,大量使用並管理了這些堆外空間。例如 netty 使用了 Direct Buffer,Kafka 和 RocketMQ 使用了 Direct Buffer 和 MMap Buffer。他們都是提前從系統申請好一塊記憶體,之後管理起來並使用。在空間不足時,繼續向系統申請,並且也會有縮容。例如 netty,在使用的 Direct Buffer 達到`-XX:MaxDirectMemorySize`的限制之後,則會先嚐試將不可達的Reference物件加入Reference連結串列中,依賴Reference的內部守護執行緒觸發可以被回收DirectByteBuffer關聯的Cleaner的run()方法。如果記憶體還是不足, 則執行`System.gc()`,期望觸發`full gc`,來回收堆記憶體中的`DirectByteBuffer`物件來觸發堆外記憶體回收,如果還是超過限制,則丟擲`java.lang.OutOfMemoryError`. # 2. 使用了 WeakReference, SoftReference 的程式,需要相應的 GC 回收。 對於 WeakReference,只要發生 GC,無論是 Young GC 還是 FullGC 就會被回收。SoftReference 只有在 FullGC 的時候才會被回收。當我們程式想主動對於這些引用進行回收的時候,需要能觸發 GC 的方法,這就用到了`System.gc()`。 # 3. 測試,學習 JVM 機制的時候 有些時候,我們為了測試,學習 JVM 的某些機制,需要讓 JVM 做一次 GC 之後開始,這也會用到`System.gc()`。 > **微信搜尋“我的程式設計喵”關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer**: >![image](https://zhxhash-blog.oss-cn-beijing.aliyuncs.com/qr-co