2

I'm using SWIG 2.0.10 in Ubuntu to call C++ code in Java.

My C++ code is:

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

The processImage function definition is:

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;

}

So, to generate the jni code using swig, i've used the following swig file (note: the vector.i file was created using this example ) :

%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>;

And this generates in the swig_wrap file the next function:

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

which is called in the delete ImageProperties c++ function.

However, running the following code in Java never releases the memory (calling the function delete_imgprops) allocated in C++:

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

So, after analyzing the code flow, i found the reason why the memory isn't released. The ImageProperties.Java file generated by SWIG contains, among others, the delete function:

public synchronized void delete() {
   if (swigCPtr != 0) {
     if (swigCMemOwn) {
       swigCMemOwn = false;
       CBIRJNI.delete_ImageProperties(swigCPtr);
     }
     swigCPtr = 0;
   }
}

The line "CBIRJNI.delete_ImageProperties(swigCPtr);" is never called because the var swigCMemOwn is always false.

I understand that because the Java side doesn't alloc memory so it also doesn't release it, so what can i do to ensure that java releases memory without any modification on java files generated by swig?

The solution that i found to release the memory is to comment the if(swigCMemOwn) test on delete() function, but i don't think that it's the best way of do it!

Thanks, Sérgio

Community
  • 1
  • 1
Sergio
  • 143
  • 12

2 Answers2

4

You could check out the

%newobject

directive (in swig 2.0) with a factory method. It tells swig that a particular function will return a new object and that the java proxy class should be responsible for cleaning up the c++ memory as well. The generated code will set swigCMemOwn to true resulting in the c++ destructor being called.

If you do call the delete method yourself, that's fine - you just have to change your style of programming to think of the swig'ed object as something like a file handle or a db connection. You call close() on those objects when you're done because you don't want to wait for java's GC to kick in at some unknown later point and collect this expensive resource- you want to manage it manually.

But you also obviously must remember to exercise good code discipline to make sure you don't use the java object anywhere after calling delete()

Clive Saha
  • 123
  • 8
0

You should never call delete() manually. If you correctly implemented C++ destructor (or wherever you memory is freed) the memory will be released as soon as the Java wrapper object is released, SWIG wrapper code then will call appropriate method automatically. Read more at SWIG doc for Java.

Alexander Solovets
  • 2,447
  • 15
  • 22
  • I call delete() manually just in the tests phase, to see if the memory is released or not (because in this tests phase i have a small program that exists before the calling of the garbage collector). But my main doubts are what should i change in swig file (or even in the c++ implementation) to ensure that the memory is released on delete() method without any modification. – Sergio Jan 12 '14 at 21:50
  • The docs actually say: "*Ideally* you need not call delete()". While you are correct that the Java wrapper will call delete() for you when it is garbage collected, it is important to note that this will only happen after its last reference is freed *and* a garbage collection cycle runs -- which might never happen! If it is important that your C++ destructors run as soon as you are done with the object, you will want to call delete() manually -- e.g. when your C++ classes use RAII-style resource management, or when they hold large blocks of C++ heap that the JVM cannot see. – jcl Jan 31 '18 at 16:32