HOWTO · Java

Java 中用於垃圾回收的 System.gc()

本教程演示瞭如何在 Java 中使用 System.gc() 進行垃圾收集。

本頁內容

System.gc() 是 Java 虛擬機器(JVM)的 Java API 呼叫,用來請求垃圾回收。它等同於呼叫 Runtime.getRuntime().gc()。這項請求不會直接刪除物件或清除變數。只有當程式無法再透過存活中的參照存取某個物件時,該物件才符合回收條件;至於是否回收以及何時回收,則由 JVM 決定。

理解 System.gc() 時,應將它視為提出請求的機制,而不是保證釋放記憶體的命令。呼叫之後,程式仍可能持有參照,JVM 也可能延後或略過回收。這項請求不保證使用特定的垃圾回收器、回收特定數量的記憶體、造成特定長度的暫停,或與其他執行階段工作依特定順序進行。

System.gc() 的作用

這項呼叫會請求 JVM 嘗試回收已無法存取的物件所佔用的記憶體。它不會移除仍在使用中的物件,也不會讓變數自動釋放參照。例如,若某個集合仍可從靜態欄位或存活中的堆疊框架存取,單是提出回收請求,並不會讓該集合符合回收條件。

診斷記憶體使用情況時,這項區別很重要。提出請求後,若物件仍可存取,或 JVM 尚未回收物件,已使用的堆積空間可能仍然偏高。另外,JVM 可能保留已回收的堆積空間,讓它繼續處於已提交狀態,以供之後配置使用;這是已提交的堆積空間,不是已使用的堆積空間。System.gc() 正常返回,並不代表它回報了已回收的位元組數。

如何在 Java 中呼叫 System.gc()

有明確理由要提出請求時,可以直接呼叫這個靜態方法。以下簡短的 Java 程式會提出一次請求,接著印出一則訊息。這則訊息只表示呼叫之後程式繼續執行,並不能證明有任何物件已被回收。請執行以下範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

public class SystemGcRequest {
    public static void main(String[] args) {
        System.gc();
        System.out.println("Returned from the garbage-collection request.");
    }
}
Returned from the garbage-collection request.

這個範例不會測量任何物件是否仍可被存取,因此無法證明記憶體已經回收。保持範例簡短,可以清楚呈現 API 呼叫,也不會暗示特定數量的記憶體或特定物件一定會被回收。

為什麼垃圾回收請求不保證回收

System.gc() 會請求執行階段嘗試進行垃圾回收。官方 Java API 文件中關於 System.gc() 的說明將此呼叫描述為對 JVM 的建議,並未保證會回收特定物件或特定數量的記憶體。方法正常返回也不代表回收已完成。執行階段設定還可能停用明確的垃圾回收請求。因此,應用程式的正確性不能依賴這項呼叫在指定時間釋放記憶體。

終結處理不是驗證請求是否生效的可靠方法。終結方法可能很晚才執行,也可能在程式結束前完全不執行;其執行順序同樣沒有保證。在終結方法中印出訊息,無法證明某次呼叫造成了一次回收。不要以終結方法的輸出、固定的回收次數,或回收前後的堆積讀值,作為呼叫已生效的證據;其他執行階段活動以及測量時機都會影響這些觀察結果。

何時使用 System.gc()

大多數應用程式程式碼應讓 JVM 自行管理垃圾回收。反覆呼叫 System.gc() 可能增加工作量或暫停時間,卻未必改善程式的記憶體使用情況;用它管理快取,也不能取代移除項目或釋放參照。應用程式資料宜採用明確的所有權管理與淘汰政策。

在受控情境中,若操作人員或工具有明確理由要求執行階段嘗試回收,例如互動式診斷流程,提出請求可能是合適的做法。請把它視為盡力而為的提示,並使用合適的 JVM 監控或效能分析工具,在操作前後測量工作負載。若記憶體仍然偏高,請調查哪些物件仍可被存取,以及參照保留在哪裡。不要讓程式的正確行為依賴 System.gc() 或終結處理的執行時機。