You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JNI场景下Java已废弃finalize方法的替代实现方案问询

JNI中C++堆内存对象的自动释放方案(替代废弃的finalize())

在JNI双向通信场景中,C++侧通过new创建的堆对象指针传递到Java后,需要确保该对象能被正确delete以避免内存泄漏。Java 9及以后finalize()方法已废弃,可通过以下两种方案实现自动/可控的内存释放:

方案一:使用Java Cleaner类(推荐)

Cleaner是Java 9引入的官方替代finalize()的机制,通过为对象注册清理动作,当对象被垃圾回收器标记为可回收时,Cleaner会异步执行清理逻辑,调用JNI方法释放C++内存。

修改后的Java代码

import java.lang.ref.Cleaner;

public class History {
    private static final Cleaner CLEANER = Cleaner.create();
    private final Cleaner.Cleanable cleanable;
    public long historyPointer;

    public History(long historyPointer){
        this.historyPointer = historyPointer;
        // 注册清理动作:当对象被回收时,调用deleteHistory释放C++内存
        this.cleanable = CLEANER.register(this, new CleanupTask(historyPointer));
    }

    native void deleteHistory(long historyPtr);

    // 静态内部类作为清理任务,避免持有外部类的强引用,防止内存泄漏
    private static class CleanupTask implements Runnable {
        private final long ptr;

        CleanupTask(long ptr) {
            this.ptr = ptr;
        }

        @Override
        public void run() {
            // 调用JNI方法释放C++对象
            new History(ptr).deleteHistory(ptr);
        }
    }
}

说明

  • Cleaner通过静态内部类CleanupTask执行清理逻辑,避免了finalize()可能导致的内存泄漏问题;
  • 清理动作是异步执行的,由Cleaner的后台线程处理,不会阻塞垃圾回收;
  • C++侧的代码无需修改,保持你现有的toJavaHistory和deleteHistory实现即可。

方案二:实现AutoCloseable接口,手动+兜底释放

如果需要更可控的资源释放时机,可以让History类实现AutoCloseable接口,结合try-with-resources语法手动释放,同时搭配Cleaner做兜底,防止用户忘记调用close方法。

修改后的Java代码

import java.lang.ref.Cleaner;

public class History implements AutoCloseable {
    private static final Cleaner CLEANER = Cleaner.create();
    private final Cleaner.Cleanable cleanable;
    public long historyPointer;
    private boolean closed = false;

    public History(long historyPointer){
        this.historyPointer = historyPointer;
        this.cleanable = CLEANER.register(this, new CleanupTask(historyPointer));
    }

    native void deleteHistory(long historyPtr);

    @Override
    public void close() {
        if (!closed) {
            deleteHistory(historyPointer);
            cleanable.clean(); // 主动清理,避免Cleaner重复执行
            closed = true;
        }
    }

    private static class CleanupTask implements Runnable {
        private final long ptr;

        CleanupTask(long ptr) {
            this.ptr = ptr;
        }

        @Override
        public void run() {
            new History(ptr).deleteHistory(ptr);
        }
    }
}

使用示例(try-with-resources)

// 使用try-with-resources,自动调用close方法释放资源
try (History history = getHistoryFromJNI()) {
    // 业务逻辑处理
} catch (Exception e) {
    // 异常处理
}

说明

  • try-with-resources会自动在代码块结束时调用close()方法,确保C++内存及时释放;
  • 搭配Cleaner做兜底,即使用户未手动调用close(),垃圾回收时仍会触发清理,避免内存泄漏;
  • C++侧代码保持不变。

内容的提问来源于stack exchange,提问作者Bhuvaneshwaran Ilanthirayan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:45:04