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对象中不使用任何对象。
您不应该手动呼叫