SWIG/Java: 对象过早被 GCed
SWIG/Java: Object gets GCed too early
我正在使用 SWIG 围绕一些 C++ 代码编写一个 Java 包装器。绑定现在可以使用,但不幸的是,我在本机端创建的对象释放得太快了。
代码从下到上:
C++: GitHub
// ...
base::Model *LoadVirtual(const char *file_name, const Config &config = Config(),
ModelType if_arpa = PROBING);
// ...
痛饮: GitHub
namespace lm::ngram {
// ...
lm::base::Model* LoadVirtual(const char *file_name,
const lm::ngram::Config &config = lm::ngram::Config());
}
Java: GitHub
public class Model {
private com.github.jbaiter.kenlm.jni.Model cModel;
private String path;
//...
public Model(String path, Config config) throws ModelException {
this.path = path;
this.cModel = KenLM.LoadVirtual(path, config.getCConfig());
}
public long getOrder() {
return this.cModel.Order();
}
//...
}
有问题的测试用例:GitHub
@Test
public void getOrder() throws Exception {
Model model = new Model(toy0Url.getPath());
assertEquals(model.getOrder(), 3);
}
测试失败并抛出 NullPointerException
,因为 model.cModel
是 null
。但是,当我在 Model
构造函数中设置断点时,字段设置正确并且 getOrder
returns 预期结果。但是,一旦离开构造函数的范围,我的 Model
class 上的 所有字段 就会突然变成 null
。 cModel
是 null
可能是因为我对 SWIG 的内存管理缺乏了解,但 path
字段也是 null
的事实确实令人费解对我来说。
您可能正在创建新对象只是为了与 Java 端一起使用(本机端没有对该对象的引用)。
如果为真,那么您需要指定此方法创建将遵循 java lifetime/gc
的新对象
%newobject lm::base::Model* LoadVirtual(const char *file_name,
const lm::ngram::Config &config = lm::ngram::Config());
有关它的更多信息,您可以在 swig 文档中找到:http://www.swig.org/Doc1.3/Customization.html#ownership
根本原因实际上是我的 Java 代码中的一个错误,与 SWIG 本身无关。
我有两个 Model
class 的构造函数,其中一个用 new Model(args)
而不是 this(args)
调用另一个。当然,这会立即丢弃正确初始化的实例并给我留下未初始化的对象(所有内容都是 null
)。
我正在使用 SWIG 围绕一些 C++ 代码编写一个 Java 包装器。绑定现在可以使用,但不幸的是,我在本机端创建的对象释放得太快了。
代码从下到上:
C++: GitHub
// ...
base::Model *LoadVirtual(const char *file_name, const Config &config = Config(),
ModelType if_arpa = PROBING);
// ...
痛饮: GitHub
namespace lm::ngram {
// ...
lm::base::Model* LoadVirtual(const char *file_name,
const lm::ngram::Config &config = lm::ngram::Config());
}
Java: GitHub
public class Model {
private com.github.jbaiter.kenlm.jni.Model cModel;
private String path;
//...
public Model(String path, Config config) throws ModelException {
this.path = path;
this.cModel = KenLM.LoadVirtual(path, config.getCConfig());
}
public long getOrder() {
return this.cModel.Order();
}
//...
}
有问题的测试用例:GitHub
@Test
public void getOrder() throws Exception {
Model model = new Model(toy0Url.getPath());
assertEquals(model.getOrder(), 3);
}
测试失败并抛出 NullPointerException
,因为 model.cModel
是 null
。但是,当我在 Model
构造函数中设置断点时,字段设置正确并且 getOrder
returns 预期结果。但是,一旦离开构造函数的范围,我的 Model
class 上的 所有字段 就会突然变成 null
。 cModel
是 null
可能是因为我对 SWIG 的内存管理缺乏了解,但 path
字段也是 null
的事实确实令人费解对我来说。
您可能正在创建新对象只是为了与 Java 端一起使用(本机端没有对该对象的引用)。 如果为真,那么您需要指定此方法创建将遵循 java lifetime/gc
的新对象%newobject lm::base::Model* LoadVirtual(const char *file_name,
const lm::ngram::Config &config = lm::ngram::Config());
有关它的更多信息,您可以在 swig 文档中找到:http://www.swig.org/Doc1.3/Customization.html#ownership
根本原因实际上是我的 Java 代码中的一个错误,与 SWIG 本身无关。
我有两个 Model
class 的构造函数,其中一个用 new Model(args)
而不是 this(args)
调用另一个。当然,这会立即丢弃正确初始化的实例并给我留下未初始化的对象(所有内容都是 null
)。