2012-02-01 2 views
4

У меня есть библиотека C++, которая вызывается Java через интерфейс на основе SWIG. На стороне Java я создаю структуру, содержащую указатели на массивы других структур, используя интерфейс структуры по умолчанию и carrays.i's %array_class.Члены SWIG-структуры досрочно освобождаются сборщиком мусора Java

Поскольку сборщик мусора Java не осведомлен о членах структуры верхнего уровня, массив иногда освобождается, где его финализатор delete[] имеет свою резервную память. Мне нужно обойти это, желательно без дублирования структуры на Java, поскольку она довольно большая.

Минимальный пример выглядит следующим образом (хотя это, вероятно, не вызовет ошибку, так как он ничего не делает):

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); 
    } 
} 

ответ

2

Существует несколько возможных решений. Самое простое - обернуть функцию, которая может создать object с без «владения» памяти Java. Это может выглядеть примерно так:

%inline %{ 
object *new_object() { 
    // SWIG will assume that it doesn't own this 
    return new object; 
} 
%} 

Вы действительно можете изменить swigCMemOwnboolean после создания. Типовая карта должна иметь возможность вводить ее в соответствующее место (когда object передается setitem). Например, вы могли бы написать:

%typemap(javacode) object %{ 
    object transfer() { 
    swigCMemOwn = false; 
    return this; 
    } 
%} 

Это должно быть до того, как object класс впервые увидел и позволяет писать что-то вроде:

os.setitem(i, o.transfer()); 

вместо os.setitem(i, o);.


вариация на эту тему было бы использовать javain TypeMap заменить реализацию по умолчанию setitem в прокси Java таким образом, что она вызывает функцию (вы поставку) на object изменить владельца, например:

%javamethodmodifiers objectArray::setitem "protected"; 
%rename objectArray::setitem setitemImpl; 

%typemap(javacode) objectArray %{ 
    public void setitem(int i, object o) { 
    o.disown(); 
    setitemImpl(i, o); 
    } 
%} 

перед %include "carrays.i" и соответствующей disown() через %typemap(javacode) object. (swigCMemOwn - protected, поэтому objectArray не может изменить это напрямую).


Возможны и другие подходы, которые также включают настройку владения. Однако те, которые я показал, являются самыми легкими.

В качестве альтернативы, другая общая работа будет состоять из keep a reference to the Java proxy Object hanging around путем присвоения ей переменной-члену. В этом случае, поскольку у вас потенциально есть много объектов, которые должны были быть самим контейнером.

Смежные вопросы