I have a Java-Application, that merges some large files. The Java-Application isn't under my control. The result from the Java-Applicationis returned as a approimatly 90 Mb large string to my C++ Program where I use it in some algorythms. I call the execute-mathod several times. My problem is, every time I call the Java-Application it reserves more memory but doesnt free it. From this Garbage collection and JNI call question I had the idea to call the garbage collector manually but it frees no memory. Any idea to fix that problem?
Here is my C++-Program
void JavaWrapperClass::CreateVM(string Classpath)
{
Classpath.insert(0,"-Djava.class.path=");
// Pointer to native interface
//================== prepare loading of Java VM ============================
JavaVMInitArgs vm_args; // Initialization arguments
JavaVMOption* options = new JavaVMOption[2]; // JVM invocation options
options[0].optionString =const_cast<char*>(Classpath.c_str()); // where to find java .class
string maxMemOption=string("-Xmx")+to_string(logicalSolverMaxMem)+"m";
options[1].optionString=const_cast<char*>(maxMemOption.c_str());
vm_args.version = JNI_VERSION_1_8; // minimum Java version
vm_args.nOptions = 2; // number of options
vm_args.options = options;
vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail
//=============== load and initialize Java VM and JNI interface =============
jint rc = JNI_CreateJavaVM(&jvm, (void**) &env, &vm_args); // YES !!
delete options; // we then no longer need the initialisation options.
if (rc != JNI_OK)
{
throw bad_exception();
}
}
const string* JavaWrapperClass::Execute(const string& Filename, const string& HV, const string& NV,
const string& FileId)
{
mergedFilesStr.erase();
mergedFilesStr.shrink_to_fit();
jclass javaClass = env->FindClass("Path_to/My_Class"); // try to find the class
if (javaClass == nullptr)
{
throw JavaWrapper_JNI_runtime_exception("class Path_to/My_Class not initialized!");
}
jmethodID ctor = env->GetMethodID(javaClass, "<init>", "()V"); // FIND AN OBJECT CONSTRUCTOR
if (ctor == nullptr)
{
env->DeleteLocalRef(javaClass);
throw JavaWrapper_JNI_runtime_exception("Constructor not found");
}
jobject javaObject;
javaObject = env->NewObject(javaClass, ctor);
if (javaObject==nullptr)
{
env->DeleteLocalRef(javaClass);
throw JavaWrapper_JNI_runtime_exception("Could not create Java-Object");
}
jmethodID mid =
env->GetMethodID(javaClass, "execute",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); // find method
if (mid == nullptr)
{
env->DeleteLocalRef(javaObject);
env->DeleteLocalRef(javaClass);
throw JavaWrapper_JNI_runtime_exception("Method string execute(String odx_Filename, String HV, String NV, String FileId) not found !");
}
else
{
logger->debug("Found JAVA method execute. => Call execute");
jstring filename = env->NewStringUTF(Filename.c_str());
jstring hv = env->NewStringUTF(HV.c_str());
jstring nv = env->NewStringUTF(NV.c_str());
jstring FileId = env->NewStringUTF(FileId.c_str());
jstring retString = (jstring) env->CallObjectMethod(javaObject,
mid, filename, hv, nv, FileId); // call the method "execute" with arguments.
jboolean isCopy=JNI_TRUE;
const char *mergedFilesPtr;
mergedFilesPtr = env->GetStringUTFChars(retString, &isCopy);
mergedFilesStr= new string(mergedFilesPtr);
if (isCopy == JNI_TRUE)
{
//Release memory from Return-String
env->ReleaseStringUTFChars(retString, mergedFilesPtr);
}
callGarbageCollector();
env->DeleteLocalRef(filename);
env->DeleteLocalRef(hv);
env->DeleteLocalRef(nv);
env->DeleteLocalRef(FileId);
}
env->DeleteLocalRef(javaObject);
env->DeleteLocalRef(javaClass);
callGarbageCollector();
return &mergedFilesStr;
}
void JavaWrapperClass::callGarbageCollector()
{
jclass systemClass = nullptr;
jmethodID systemGCMethod = nullptr;
systemClass = env->FindClass("java/lang/System");
systemGCMethod = env->GetStaticMethodID(systemClass, "gc", "()V");
env->CallStaticVoidMethod(systemClass, systemGCMethod);
env->DeleteLocalRef(systemClass);
}