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
相关产品推荐
相关产品推荐

