回调是否会在 JNI 函数内复制 jnienv、jinstance?
我传递给构建器的 lambda 被填充到 className 对象中,并定期(每小时)调用以刷新其他成员。第一次就被成功调用。我不确定 lambda 是否保留 env
、instance
来合法调用反向 JNI 函数?
JNIEXPORT jint JNICALL
Java_com_company_app_ClassName_JniInit(JNIEnv *env, jobject instance){
int data = 0;
auto builder = new Builder(data,
[env, instance]() -> std::string {
std::string stringObj = populateData(env, instance); // This function makes a reverse JNI call to get data from a java function in the class
return stringObj;
}
);
std::shared_ptr<className> = builder->build();
return 1;
}
我似乎收到了 SIGNAL 11 错误,SIGSEGV。这种分段错误是否可以以任何方式捕获,以便应用程序不会崩溃?
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), failure addr 0x228 in tid 21785 (ClassName), pid 21573 (.company.app)
它似乎在 内的这一行崩溃populateData
-
jstring data = (jstring)(env)->CallObjectMethod(instance, java函数名);
有没有办法在调用之前检查该函数是否会失败?我检查了 env
(populateData
中的 JNIEnv*
参数)是否为 NULL
,但它不是,并且有一个有效的地址以及 instance
(populateData
中的 jinstance
参数)。
The lambda that I pass to builder is populated into className
object, and called at regular intervals (every hour) of time to refresh the other members. It gets called the first time successfully. I'm not sure if the lambda retains env
, instance
to legally call the reverse JNI function?
JNIEXPORT jint JNICALL
Java_com_company_app_ClassName_JniInit(JNIEnv *env, jobject instance){
int data = 0;
auto builder = new Builder(data,
[env, instance]() -> std::string {
std::string stringObj = populateData(env, instance); // This function makes a reverse JNI call to get data from a java function in the class
return stringObj;
}
);
std::shared_ptr<className> = builder->build();
return 1;
}
I seem to be getting a SIGNAL 11 error, SIGSEGV. Is this kind of segmentation fault catchable in any way, so the app doesn't crash?
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x228 in tid 21785 (ClassName), pid 21573 (.company.app)
It seems to be crashing at this line inside populateData
-
jstring data = (jstring)(env)->CallObjectMethod(instance, javaFunctionName);
Is there a way to check if this function will fail before calling it? I checked if env
(JNIEnv*
argument in populateData
) is NULL
, but its not, and has a valid address along with instance
(jinstance
argument in populateData
).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果此函数异步执行某些操作,您将遇到 jobject 实例的问题。原因是在该函数启动之前,Java将该对象标记为具有额外的引用。当它返回时它会删除它。因此,在它返回后,如果 Java 代码中没有其他实例,则该对象可以被垃圾收集器清理。
可以通过在主线程上启动异步函数之前调用 NewGlobalRef(JNIEnv *env, jobject obj) 以及在 jobject 时回调结束时调用
DeleteGlobalRef
来修复此问题不再需要。You'll have problems with jobject instance if this function does something asynchronously. The reason is that before this function is started, Java marks the object as having an extra reference. It removes that when it returns. So after it returns, the object can be cleaned up by the garbage collector if there's no other instances in the Java code.
This can be fixed by calling
NewGlobalRef(JNIEnv *env, jobject obj)
before starting the async function on the main thread, and callingDeleteGlobalRef
at the end of the callback when jobject is no longer needed.为了回答这个问题,我发现了一种稍微不同的黑客方法。
不要复制
JNIEnv
和object
或创建对它们的引用。一旦您的 JNI 函数超出范围,它们就会被删除。我不确定为什么复制不起作用(如果有人能回答这个问题,那就太好了)。或者,我使用JavaVM*
来维护 jvm 的本地引用,您可以在JNI_OnLoad
中执行此操作。使用下面的函数,它会工作得很好。
如果您需要类实例,则需要通过 JNIEnv 初始化它,但我的类使用静态方法,因此我只是使用 env->FindClass< 获取该类/code> 然后您可以执行
env->GetStaticMethodID
以及env->CallStaticObjectMethod
。To answer this question, I have found a slightly different kind of hack.
Don't copy the
JNIEnv
, andobject
or create references to them. They get deleted as soon as your JNI function goes out of scope. I'm not sure why copying doesn't work (if someone could answer this, that would be great). Alternatively, I've usedJavaVM*
to maintain a local reference of the jvm, you can do this in yourJNI_OnLoad
.Use the function below, and it would work fine.
If you need the class instance, you'll need to initialise it via
JNIEnv
, but I use a static method for my class, so I just fetched the class usingenv->FindClass
and then you can doenv->GetStaticMethodID
along withenv->CallStaticObjectMethod
.