Members of a SWIG are released early by the Java garbage collector

I have a C ++ library that is called by Java through the SWIG interface. On the Java side, I create a structure containing pointers to arrays of other structures using the default structure interface and carrays.i %array_class .

Since the Java garbage collector does not know about the members of the top-level structure, the array is sometimes freed, and its finalizer delete[] is its backup memory. I need a way around this, preferably without duplicating the structure in Java, since it is quite large.

A minimal example looks like this (although it probably won't throw an error, since it's not strong):

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); } } 
+4
source share
1 answer

There are several possible solutions. The simplest thing is to wrap a function that can create an object without using Java "memory". It might look something like this:

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

In fact, you can change swigCMemOwn boolean after creating. The map-map should be able to enter it in the appropriate place (when the object is passed setitem ). For example, you can write:

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

This should be before the object class is first noticed and allows you to write something like:

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

instead of os.setitem(i, o); .


A variation on this topic would be to use javain typemap to replace the default implementation of setitem in a Java proxy so that it calls the function (you supply) on object to change ownership, for example

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

up to %include "carrays.i" and the corresponding disown() via %typemap(javacode) object . ( swigCMemOwn is protected , so objectArray cannot directly change this.)


There are other approaches that also include setting up ownership. The ones I showed are the easiest I think.

Alternatively, another common job would be to maintain a reference to the Java proxy object hanging around , assigning it to a member variable. In this case, since you have potentially a lot of objects that should have been the container itself, though.

+2
source

Source: https://habr.com/ru/post/1394239/


All Articles