gpt4 book ai didi

java - 删除对象分配 JNI 调用 API 中的 jobject 引用

转载 作者:行者123 更新时间:2023-11-28 04:30:06 26 4
gpt4 key购买 nike

我想执行以下循环:

for(absolute_date CURRENT_DATE = START_DATE; CURRENT_DATE.COMPARE_TO(END_DATE) <= 0; CURRENT_DATE.SHIFT_SELF(TIMESTEP))
{
CURRENT_STATE = Propagator.PROPAGATE(CURRENT_DATE);
}

其中 CURRENT_STATEstate 类的对象。 propagator::PROPAGATE() 是一种返回 state 类对象的方法。

我的 state 类实际上是我通过 JNI 调用 API 调用的 Java 库类的类包装器。我遇到的问题是我想用 DeleteLocalRef 删除本地 java 引用以防止内存泄漏(特别重要,因为我将循环数千次)。

但是,由于在我的 state 类析构函数中调用了 DeleteLocalRef,因此当赋值的 RHS 返回时,对 java jobject 的引用被销毁,从而使 CURRENT_STATE 无效,因为它包含对已删除的工作项目的引用。

如何避免这种情况?

@Wheezil

关于您的第一点——因为我正在使用调用 API,即在 C++ 中创建一个虚拟机并调用 Java 函数,我认为我不需要转换为全局引用(因为所有本地引用在 JVM 启用之前仍然有效)销毁或直到线程被分离)。在这种情况下,我不会分离线程并将其重新附加到 JVM,因此本地引用永远不会被删除。对我来说重要的是确保在 JVM 中删除本地引用。

关于第二点 - 我已经通过设置我的复制构造函数/赋值运算符 = delete 来禁止复制。我的问题更具体地是关于如何确保删除这些引用。

我的状态类如下所示:

state::state(JNIEnv* ENV)
{
this->ENV = ENV;
this->jclass_state = ENV->FindClass("/path/to/class");
this->jobject_state = nullptr;
}

state::~state()
{
if(DOES_JVM_EXIST())
{
ENV->DeleteLocalRef(this->jclass_state);
ENV->DeleteLocalRef(this->jobject_state); //PROBLEMATIC
}
}

state::state(state&& state_to_move)
{
this->ENV = state_to_move.ENV;

//move jobjects from mover => new object
this->jobject_state = state_to_move.jobject_state;
this->jclass_state = state_to_move.jclass_state;
}

state& state::operator =(state&& state_to_move)
{
this->ENV = state_to_move.ENV;

//move jobjects from mover => current object
this->jobject_state= state_to_move.jobject_state;
this->jclass_state = state_to_move.jclass_state;
return *this;
}

更详细地描述我面临的问题:propagator::PROPAGATE() 方法按值返回一个state 对象(当前堆栈已分配)。一旦此函数返回,就会发生以下情况:

1) 移动赋值运算符被调用。这会在 CURRENT_STATE 对象中设置 jobject_statejclass_state 成员。

2) 为在 PROPAGATE() 函数中创建的 state 实例调用析构函数。这会删除对 j​​object_state 的本地引用,因此 CURRENT_STATE 对象不再具有有效的成员变量。

最佳答案

从哪里开始... JNI 非常挑剔和无情,如果你不把事情做好,它就会崩溃。您的描述相当单薄(如果这没有帮助,请提供更多详细信息),但我可以做出很好的猜测。你的方法有几个问题。你大概在做这样的事情:

struct state {
state(jobject thing_) : thing(thing_) {}
~state() { env->DeleteLocalRef(thing); }
jobject thing;
}

第一个问题是存储本地引用是危险的。您不能在当前 JNI 框架之外挂起它们。所以将它们转换为全局:

struct state {
state(jobject thing_) : thing(env->NewGlobalRef(thing_)) {
env->DeleteLocaLRef(thing_);
}
~state() { env->DeleteGlobalRef(thing); }
jobject thing;
}

第二个问题是 jobject 基本上就像旧的 C++ auto_ptr<> —— 真的不安全,因为复制它会导致悬空指针和双重释放。所以你要么需要禁止复制状态并且可能只传递状态*,要么制作一个有效的复制构造函数:

state(const state& rhs) thing(env->NewGlobalRef(rhs.thing)) {}

这至少应该让您走上正轨。

更新:Ddor,关于本地与全局引用,this link描述得很好:“当执行从创建本地引用的本地方法返回时,本地引用变得无效。因此,本地方法不得存储本地引用并期望在后续调用中重用它。”您可以保留本地引用,但只有在严格的情况下。请特别注意,您不能将这些交给另一个线程,而您似乎没有这样做。另一件事——可以激活的本地引用总数是有限制的。令人沮丧的是,此限制未指定,但它似乎是特定于 JVM 的。我建议谨慎并始终转换为全局。

我以为我在某处读到过,您不需要删除 jclass,因为 FindClass() 总是返回相同的东西,但我很难验证这一点。在我们的代码中,我们也始终将 jclass 转换为全局引用。

ENV->DeleteLocalRef(this->jclass_state); 

我必须承认对 C++ 移动语义的无知;只需确保未调用默认复制构造函数并且您的 jobject_state 未被释放两次。

this->jobject_state = state_to_move.jobject_state;

如果你的移动构造函数被调用而不是复制构造函数或赋值,我不知道你为什么会在临时对象的销毁时看到删除。正如我所说,我不是移动语义方面的专家。我总是让复制构造函数创建一个新的全局变量。引用。

关于java - 删除对象分配 JNI 调用 API 中的 jobject 引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53176990/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com