2012-02-01 48 views
4

我有一個C++庫,由Java通過基於SWIG的接口調用。在Java方面,我使用默認的結構接口和carrays.i%array_class構建了一個包含指向其他結構數組的指針的結構。SWIG結構成員被Java的垃圾收集器過早釋放

因爲Java的垃圾收集器不知道頂層結構的成員,所以有時會釋放該數組,其數組有時會被釋放,其終結符delete[]就是它的後備內存。我需要一種解決方法,最好不要在Java中重複結構,因爲它相當大。

小例子看起來是這樣的(雖然它可能不會引發錯誤,因爲它並沒有做太多):

C++ /痛飲:

%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

有幾個可能的解決方案。最簡單的方法是包裝一個函數,該函數可以在沒有Java「擁有」內存的情況下創建object。這可能看起來像:

%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類型映射替換Java代理默認setitem實現,使得它呼籲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"和經由%typemap(javacode) object相應disown()之前。 (swigCMemOwnprotected,所以objectArray不能直接修改)。


還有其他方法可能也涉及設置所有權也。我展示的是我認爲最簡單的。

或者,另一個常見的解決方法是將keep a reference to the Java proxy Object hanging around分配給成員變量。在這種情況下,因爲你可能有很多的對象,但它本身必須是一個容器。