首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 對象銷毀與垃圾回收機制深度解析:finalize、引用類型與 GC 根

     編輯:Java 相關知識

對象生命週期與作用域

Java 變量分兩類:

  • 基本類型變量:直接存值,棧上分配,作用域結束即銷毀
  • 引用類型變量:存對象地址,對象在堆上,引用在棧上

對象生命週期**不等於**引用變量作用域:


void method() {
    Object obj = new Object(); // obj 在棧上,對象在堆上
    List list = new ArrayList();
    list.add(obj); // list 持有 obj 引用
} // obj 引用銷毀,但對象被 list 引用,存活

垃圾回收核心判定:可達性分析

JVM 通過 **GC Roots** 作為起點,向下搜索引用鏈:

  • 虛擬機棧局部變量引用的對象
  • 方法區類靜態屬性/常量引用的對象
  • 本地方法棧 JNI 引用的對象
  • 活躍線程引用的對象
  • 同步鎖持有的對象

**可達 = 存活,不可達 = 垃圾**。標記-清除/標記-整理/複製算法均基於此。

finalize() 方法:已棄用的「終結者」


@Deprecated(since="9")
protected void finalize() throws Throwable {
    try {
        // 釋放非內存資源:文件句柄、網絡連接、數據庫連接
        closeResources();
    } finally {
        super.finalize(); // 調用父類 finalize
    }
}

關鍵缺陷

  • 不可預測:GC 何時運行不確定,finalize 何時調用不可控
  • 無序性:對象間 finalize 順序無保證
  • 性能損耗:進入 finalize 隊列、單線程執行、延遲回收
  • 異常吞沒:finalize 拋出異常被忽略,對象仍可能被回收
  • 復活風險:finalize 中重新建立引用(this 逃逸)導致對象復活,二次 GC 才會回收

替代方案:try-with-resources / Cleaner / PhantomReference


// Java 9+ Cleaner API
public class Resource implements AutoCloseable {
    private static final Cleaner cleaner = Cleaner.create();
    private final Cleaner.Cleanable cleanable;
    private final ResourceHandle handle;
    
    public Resource() {
        this.handle = acquireHandle();
        this.cleanable = cleaner.register(this, () -> releaseHandle(handle));
    }
    
    public void close() { cleanable.clean(); }
}

四大引用類型與 GC 行為

引用類型創建方式GC 回收時機典型用途
強引用Object obj = new Object()永不回收(OOM 拋出前)常規對象持有
軟引用SoftReference<T> ref = new SoftReference<>(obj)內存不足前回收緩存、圖片載入
弱引用WeakReference<T> ref = new WeakReference<>(obj)下次 GC 必回收WeakHashMap、監聽器
虛引用PhantomReference<T> ref = new PhantomReference<>(obj, queue)隨時回收,入隊通知堆外內存釋放、Cleaner

GC 根擴展與實戰排查

常見 GC 根類型

  • JNI 全局引用
  • 類加載器
  • 線程對象
  • 同步器(Lock/Condition)
  • JVM 內部對象(系統類、異常類等)

內存洩漏典型模式


// 1. 靜態集合持有對象,生命週期 = JVM
static List cache = new ArrayList<>();
cache.add(bigObject); // 永不釋放

// 2. 監聽器未移除
eventSource.addListener(listener); // 靜態/長生命週期源持有

// 3. ThreadLocal 未清理
ThreadLocal tl = new ThreadLocal<>();
tl.set(bigData); // 線程池線程復用導致洩漏

// 4. 連接/流未關閉
Connection conn = dataSource.getConnection(); // 物理連接洩漏


GC 日誌分析關鍵指標


-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log

關鍵指標:
- Young GC 頻率/耗時
- Full GC 頻率/耗時/觸發原因
- 堆佔用率趨勢
- 存活對象年齡分佈
- 元空間/壓縮類空間變化

總結

  • 對象銷毀 = GC 回收,非確定性、非即時
  • finalize 已棄用,用 AutoCloseable/Cleaner/PhantomReference
  • 理解四種引用類型,善用軟/弱引用構建緩存
  • 內存洩漏本質:長生命週期對象持有短生命週期對象引用
  • 排查工具:jmap、jhat、MAT、JProfiler、Arthas
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved