我有一个由
Java通过基于SWIG的接口调用的C库.在Java方面,我使用默认的struct接口和carrays.i的%array_class构建了一个包含指向其他结构数组的指针的结构.
因为Java的垃圾收集器不知道顶级结构的成员,所以有时释放该数组,其终结器delete []是其后备内存.我需要解决这个问题,最好不要在Java中复制结构,因为它相当大.
一个最小的例子看起来像这样(虽然它可能不会触发bug,因为它没有做太多):
C / SWIG:
%module example
%include "carrays.i"
%array_class(object, objectArray);
struct object {
unsigned int id;
char *name;
};
struct data {
size_t nobjects;
object *objects;
};
void use_data(data*);
Java的:
public class Example {
private static data writeData() {
data d = new data();
objectArray os = new objectArray(3);
for (int i = 0; i < 3; i++) {
object o = new object();
o.setId(i);
o.setName("obj" + i);
os.setitem(i, o);
}
d.setNobjects(3);
d.setObjects(os.cast());
return d;
}
public static void main(String[] args) {
data d = writeData();
example.use_data(d);
}
}
最佳答案 这有几个可能的解决方案.最简单的是包装一个可以在没有Java“拥有”内存的情况下创建对象的函数.这看起来像是这样的:
%inline %{
object *new_object() {
// SWIG will assume that it doesn't own this
return new object;
}
%}
实际上,您可以在创建后修改swigCMemOwn布尔值.类型映射应该能够在适当的位置注入它(当对象被传递给setitem时).例如,您可以写:
%typemap(javacode) object %{
object transfer() {
swigCMemOwn = false;
return this;
}
%}
这需要在首次看到对象类之前,并允许您编写如下内容:
os.setitem(i, o.transfer());
而不是os.setitem(i,o);.
这个主题的变体是使用javain类型映射替换Java代理中的默认setitem实现,以便它调用对象上的函数(您提供)来更改所有权,例如:
%javamethodmodifiers objectArray::setitem "protected";
%rename objectArray::setitem setitemImpl;
%typemap(javacode) objectArray %{
public void setitem(int i, object o) {
o.disown();
setitemImpl(i, o);
}
%}
之前%包含“carrays.i”和相应的disown()通过%typemap(javacode)对象. (swigCMemOwn受保护,因此objectArray无法直接修改它).
还有其他方法可能,也涉及设置所有权.我展示的那些是我认为最简单的.
或者,通过将其分配给成员变量,另一个常见的工作是keep a reference to the Java proxy Object hanging around.在这种情况下,因为你可能有很多对象,但它们必须是一个容器本身.