SWIG java:释放用c ++分配的内存

SWIG java: releasing memory allocated in c++

我在Ubuntu中使用SWI2.2.10来调用Java中的C++代码。

我的C++代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//ImgPro.h:
#include <vector>

typedef struct _bin
{
    char* name;
    float value;
} Bin;

typedef struct imgprops
{
    std::vector<Bin> color;
    int width;
    int height;
    char *print;
} ImageProperties;

class ImgPro
{
public:
    ImgPro();

    ImageProperties *processImage(char* imagePath);
};

processImage函数定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ImageProperties* ImgPro::processImage(char *imagePath)
{
    ImageProperties* imgProp = new ImageProperties();
    imgProp->width = 200;
    imgProp->height = 200;

    char* fp = new char(5);
    strcpy(fp,"abc!");
    imgProp->print = fp;

    Bin outputBin1;
    char *name1 = new char(strlen("red")+1);
    strcpy(name1,"red");
    outputBin1.name = name1;
    outputBin1.value = 0.125;

    Bin outputBin2;
    char *name2 = new char(strlen("blue")+1);
    strcpy(name2,"blue");
    outputBin2.name = name1;
    outputBin2.value = 0.27;

    vector<Bin> tempVec;
    tempVec.push_back(outputBin1);
    tempVec.push_back(outputBin2);
    imgProp->color = tempVec;
    return imgProp;

}

因此,为了使用swig生成JNI代码,我使用了以下swig文件(注意:vector.i文件是使用此示例创建的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
%module CBIR

// to handle char** has String_Array in Java
%include <various.i>
%include"vector.i"

%{
   #include"ImgPro.h"
%}

// to handle char** has String_Array in Java
%apply char **STRING_ARRAY { char ** };

// memory release
%extend imgprops {
       ~imgprops(){
    if($self != NULL)
    {
        // releasing print element
        if($self->print != NULL)
            delete[] $self->print;
        // releasing vector elements
        for(uint x = 0; x < $self->color.size(); x++)
        {
                Bin currentBin = $self->color[x];
                if(currentBin.name != NULL)
                    delete[] currentBin.name;
        }
        // releasing stuct Pointer
        delete $self;
    }
}
}

%include"ImgPro.h"

%template(BinVec) std::vector<Bin>;

这将在swig_wrap文件中生成下一个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SWIGINTERN void delete_imgprops(imgprops *self){
    if(self != NULL)
    {
        // releasing print element
        if(self->print != NULL)
            delete[] self->print;
        // releasing vector elements
        for(uint x = 0; x < self->color.size(); x++)
        {
                Bin currentBin = self->color[x];
                if(currentBin.name != NULL)
                    delete[] currentBin.name;
        }
        // releasing stuct Pointer
        delete self;
    }
}

它在删除图像属性C++函数中被调用。

但是,在Java中运行下面的代码永远不会释放在C++中分配的内存(调用函数DeleTeE.IGGPROPS):

1
2
3
4
5
6
7
8
9
ImgPro imgObject = new ImgPro();
ImageProperties propObject = imgObject.processImage("imagem123-jpg");            

int width = propObject.getWidth();
int height = propObject.getHeight();
String fingerPrint = propObject.getPrint();

propObject.delete();            
imgObject.delete();

所以,在分析了代码流之后,我发现了内存没有释放的原因。Sigg生成的IMAGE属性.java文件包含删除函数:

1
2
3
4
5
6
7
8
9
public synchronized void delete() {
   if (swigCPtr != 0) {
     if (swigCMemOwn) {
       swigCMemOwn = false;
       CBIRJNI.delete_ImageProperties(swigCPtr);
     }
     swigCPtr = 0;
   }
}

从不调用行"cbirjni.delete_imageproperties(swigcptr);",因为var swigcmown始终为false。

我理解,因为Java端不分配内存,所以它也不释放它,那么我能做些什么来确保Java释放内存而不需要对SWIG生成的Java文件进行任何修改?

我发现释放内存的解决方案是在DeleTeNe()函数上注释if(SigigcMeMon)测试,但我不认为这是最好的方法。

谢谢,S


您可以查看

1
%newobject

指令(在SWIG 2中)用工厂方法。它告诉SWIG一个特定的函数将返回一个新的对象,Java代理类也应该负责清理C++内存。生成的代码会将SigigcMeMon设置为true,导致C++析构函数被调用。

如果你真的自己调用了delete方法,那没关系——你只需要改变你的编程风格,把swig'ed对象想象成一个文件句柄或数据库连接。当你完成时,你会调用这些对象的关闭(),因为你不想等待Java的GC在某个未知的后面点开机并收集这个昂贵的资源——你想手动管理它。

但是,显然,您还必须记住,在调用DeleTe()之后,要执行好的代码规则,以确保在Java对象中不使用任何对象。


您不应该手动呼叫delete()。如果您正确地实现了C++析构函数(或者在您释放内存的任何地方),一旦Java包装对象被释放,内存将被释放,SWIG包装器代码将自动调用合适的方法。阅读更多关于SWIG DOC的Java语言。