java - Shall jarrayObject (array of strings) be deleted/released after usage in a JNI call ? -
i'm experimenting in c++ jni , have doubt java object i've created in c++ being used jni call argument.
take simple java class, string array argument:
public class mytest { public static void main(string[] args) { system.out.println("hello, world in java"); int i; (i=0; i<args.length; i++) system.out.println(args[i]); } }
i call c++ following jni code:
jmethodid mid3 = env->getstaticmethodid(cls2, "main", "([ljava/lang/string;)v"); // signature string array arg. if(mid3 == nullptr) cerr << "error: method not found !" << endl; else { jobjectarray arr = env->newobjectarray(5, // constructs java array of 5 env->findclass("java/lang/string"), env->newstringutf("str")); // default value env->setobjectarrayelement( // change 1 of array elements arr, 1, env->newstringutf("myownstring")); env->callstaticvoidmethod(cls2, mid3, arr); // call method }
this works well. i'm unsure have to jarrayobject (and java strings contains) afterwards, keep things clean.
my understanding jvm responsible java objects. how know objectsz no longer need on c++ side ? googled around , didn't find clear explanation. read in jni specifications deletelocalref()
that:
local references valid duration of native method call. freed automatically after native method returns.
so shall call deletelocalref()
jarrayobject (or every java string contains) or other cleaning function ? or can assume jvm takes care of on own ?
the jni design specs (see section global , local references) explains that:
- all references passed native method references returned jni functions local references;
- these local references automatically freed after native method returns.
however, principle applies case of c++ function called java: local references released when function returns java (see section implementing local references).
if create objects or references jni functions in c++ code not called java, local references not freed automatically, causing memory leak.
so should better use deletelocalref()
free java objects created/obtained c++ no longer used.
demonsration:
the following simple java code allocates big objects without keeping references, , call memory inspection:
class bigmemoryconsumer { private char mytable[]; public bigmemoryconsumer () { // allocate , use 1mb mytable = new char[1048576]; (int i=0; i<1048576; i++) mytable[i] = (char) (i % 256); } public static long showmem() { // show memory statistics int funit = 1024*1024; string unit = " mb"; runtime runtime = runtime.getruntime(); system.gc(); // opportunity run garbage collector (not guaranteed !) long used = runtime.totalmemory() - runtime.freememory(); system.out.println("used memory: " + used / funit + unit + " ("+ (used*100/runtime.maxmemory())+"%)"); system.out.println("free memory: " + runtime.freememory() / funit + unit); system.out.println("total memory: " + runtime.totalmemory() / funit + unit); system.out.println("max memory: " + runtime.maxmemory() / funit + unit); system.out.println(""); return used; } public static void main (string[] args) { // test in java long lastmem = showmem(); (int i=0; i<256; i++) { bigmemoryconsumer m = new bigmemoryconsumer(); long mem = showmem(); if (mem<=lastmem) { system.out.println ("garbage collector freed memory"); return; } else lastmem = mem; } } }
when run class directly java (aka main()
) you'll notice java quicly (second or third iteration on 64bit system) run garbage collector: object m reinitialised on every iteration, meaning created objects no longer referenced.
now i've reproduced equivalent main()
in c++ code, after having loaded jvm , initialized jni environment:
jclass cls = env->findclass("bigmemoryconsumer"); jmethodid ctor = env->getmethodid(cls, "<init>", "()v"); // find consructor jmethodid show = env->getstaticmethodid(cls, "showmem", "()j"); // find memshow() jlong lastmem = 0; vector<jobject> v; for(int = 0; < 256; i++) { jobject myo = env->newobject(cls, ctor); v.push_back(myo); jlong mem = env->callstaticlongmethod(cls, show); if(mem <= lastmem) { cout << "attention: garbage collector called consumed java memory didn't increase after "<<i<<" iterations\n"; break; } else lastmem = mem; //env->deletelocalref(myo); ///!!!! <======= see text }
if running code without deletelocalref()
, you'll notice continuous increase in consumed memory: no garbage collection takes place, jvm not aware reference java object requested c++ no longe used.
if comment out highlighted line, deletelocalref()
tell jvm object no longer needed in c++ code, , garbage collector behave in pure java example, rfreeing object after couple of iterations.
Comments
Post a Comment