JNI 如何管理 C++ 缓冲区的生命周期
JNI how to manage the life cycle of a c++ buffer
我在我的 C++ 代码中的堆上分配了一个图像缓冲区,我想通过 JNI 与其他一些 C++ 对象以及 Java 对象共享。在本机方面,我使用 shared_ptr,我想知道最好的方法是什么?我的想法是在堆上分配一次缓冲区并在所有地方共享一个引用。我正在利用智能指针,以便在所有引用超出范围后立即释放缓冲区,但在共享对 java 端的引用时我遇到了问题。
如何确保我的 java 对象始终具有对缓冲区的有效引用?当 java 对象使用其引用完成时,c++ 如何确定引用计数器达到 0。我关心的是避免内存泄漏,并确保缓冲区在被 java class.
处理之前不会被过早销毁
感谢帮助
一般答案是"make the Java object's lifetime influence the lifetime of the C++ object"。
从以下内容开始 Java class:
class Refholder implements AutoCloseable {
private long ptr; // the actual pointer
private long shared_ptr; // a pointer to a shared_ptr keeping `ptr` alive
public Refholder(long ptr, long shared_ptr) {
this.ptr = ptr;
this.shared_ptr = shared_ptr;
}
public native void close();
public void finalize() { close(); }
// Other methods to access the contents of `ptr` go here.
};
这将包含实际指针和指向 shared_ptr
的指针。
如果您想提交对 Java 的引用,请使用以下内容:
jobject passToJava(JNIEnv *env, std::shared_ptr<Foo> instance) {
jclass cls_Refholder = env->FindClass("Refholder");
jmethodID ctr_Refholder = env->GetMethodID(cls_Refholder, "<init>", "(JJ)V");
// This line increases the reference count and remembers where we put the copy
std::shared_ptr<Foo> *copy = new std::shared_ptr<Foo>(std::move(instance));
jobject ret = env->NewObject(cls_Refholder, ctr_Refholder, copy->get(), copy);
return ret;
}
最后,close
方法负责提取shared_ptr
并释放它:
JNIEXPORT void Java_Refholder_close(JNIEnv *env, jobject obj) {
jclass cls_Refholder = env->GetObjectClass(obj);
jfieldID fld_Refholder_ptr = env->GetFieldID(cls_Refholder, "ptr", "J");
jfieldID fld_Refholder_shared_ptr = env->GetFieldID(cls_Refholder, "shared_ptr", "J");
std::shared_ptr<Foo> *copy = (std::shared_ptr<Foo>*)env->GetLongField(obj, fld_Refholder_shared_ptr);
if (!copy)
return;
env->SetLongField(obj, fld_Refholder_ptr, 0);
env->SetLongField(obj, fld_Refholder_shared_ptr, 0);
delete copy;
}
我决定同时实现 AutoCloseable
和 finalize
,因为我不知道您的 Java 代码计划如何使用引用。如果您需要对 C++ 对象进行确定性破坏,则需要使用 try-with-resources
或显式调用 close
方法。如果你不这样做,最后 finalize
将关闭它。
我在我的 C++ 代码中的堆上分配了一个图像缓冲区,我想通过 JNI 与其他一些 C++ 对象以及 Java 对象共享。在本机方面,我使用 shared_ptr,我想知道最好的方法是什么?我的想法是在堆上分配一次缓冲区并在所有地方共享一个引用。我正在利用智能指针,以便在所有引用超出范围后立即释放缓冲区,但在共享对 java 端的引用时我遇到了问题。
如何确保我的 java 对象始终具有对缓冲区的有效引用?当 java 对象使用其引用完成时,c++ 如何确定引用计数器达到 0。我关心的是避免内存泄漏,并确保缓冲区在被 java class.
处理之前不会被过早销毁感谢帮助
一般答案是"make the Java object's lifetime influence the lifetime of the C++ object"。
从以下内容开始 Java class:
class Refholder implements AutoCloseable {
private long ptr; // the actual pointer
private long shared_ptr; // a pointer to a shared_ptr keeping `ptr` alive
public Refholder(long ptr, long shared_ptr) {
this.ptr = ptr;
this.shared_ptr = shared_ptr;
}
public native void close();
public void finalize() { close(); }
// Other methods to access the contents of `ptr` go here.
};
这将包含实际指针和指向 shared_ptr
的指针。
如果您想提交对 Java 的引用,请使用以下内容:
jobject passToJava(JNIEnv *env, std::shared_ptr<Foo> instance) {
jclass cls_Refholder = env->FindClass("Refholder");
jmethodID ctr_Refholder = env->GetMethodID(cls_Refholder, "<init>", "(JJ)V");
// This line increases the reference count and remembers where we put the copy
std::shared_ptr<Foo> *copy = new std::shared_ptr<Foo>(std::move(instance));
jobject ret = env->NewObject(cls_Refholder, ctr_Refholder, copy->get(), copy);
return ret;
}
最后,close
方法负责提取shared_ptr
并释放它:
JNIEXPORT void Java_Refholder_close(JNIEnv *env, jobject obj) {
jclass cls_Refholder = env->GetObjectClass(obj);
jfieldID fld_Refholder_ptr = env->GetFieldID(cls_Refholder, "ptr", "J");
jfieldID fld_Refholder_shared_ptr = env->GetFieldID(cls_Refholder, "shared_ptr", "J");
std::shared_ptr<Foo> *copy = (std::shared_ptr<Foo>*)env->GetLongField(obj, fld_Refholder_shared_ptr);
if (!copy)
return;
env->SetLongField(obj, fld_Refholder_ptr, 0);
env->SetLongField(obj, fld_Refholder_shared_ptr, 0);
delete copy;
}
我决定同时实现 AutoCloseable
和 finalize
,因为我不知道您的 Java 代码计划如何使用引用。如果您需要对 C++ 对象进行确定性破坏,则需要使用 try-with-resources
或显式调用 close
方法。如果你不这样做,最后 finalize
将关闭它。