JNI - Passing large amounts of data between Java and Native code -
i trying achieve following:
1) have byte array on java side represents image.
2) need give native code access it.
3) native code decodes image using graphicsmagick , creates bunch of thumbnails calling resize. calculates perceptual hash of image either vector or unint8_t array.
4) once return data java side different threads read it. thumbnails uploaded external storage service via http.
my questions are:
1) efficient way pass bytes java native code? have access byte array. don't see particular advantage passing byte buffer (wrapping byte array) vs byte array here.
2) best way return these thumbnails , perceptual hash java code? thought of few options:
(i) allocate byte buffer in java , pass along native method. native method write , set limit after done , return number of bytes written or boolean indicating success. slice , dice byte buffer extract distinct thumbnails , perceptual hash , pass along different threads upload thumbnails. problem approach don't know size allocate. needed size depend on size of thumbnails generated don't know in advance , number of thumbnails (i know in advance).
(ii) allocate byte buffer in native code once know size needed. memcpy blobs right region based on custom packing protocol , return byte buffer. both (i) , (ii) seem complicated because of custom packing protocol have indicate the length of each thumbnail , perceptual hash.
(iii) define java class has fields thumbnails: array of byte buffers , perceptual hash: byte array. allocate byte buffers in native code when know exact sizes needed. can memcpy bytes graphicsmagick blob direct address of each byte buffer. assuming there method set number of bytes written on byte buffer java code knows how big byte buffers are. after byte buffers set, fill in java object , return it. compared (i) , (ii) create more byte buffers here , java object avoid complexity of custom protocol. rationale behind (i), (ii) , (iii) - given thing these thumbnails upload them, hoping save copy byte buffers (vs byte array) when uploading them via nio.
(iv) define java class has array of byte arrays (instead of byte buffers) thumbnails , byte array perceptual hash. create these java arrays in native code , copy on bytes graphicsmagick blob using setbytearrayregion. disadvantage vs previous methods there yet copy in java land when copying byte array heap direct buffer when uploading it. not sure saving thing in terms of complexity vs (iii) here either.
any advice awesome.
edit: @main suggested interesting solution. editing question follow on option. if wanted wrap native memory in directbuffer how @main suggests, how know when can safely free native memory?
what efficient way pass bytes java native code? have access byte array. don't see particular advantage passing byte buffer (wrapping byte array) vs byte array here.
the big advantage of direct bytebuffer
can call getdirectbytebufferaddress
on native side , have pointer buffer contents, without overhead. if pass byte array, have use getbytearrayelements
, releasebytearrayelements
(they might copy array) or critical versions (they pause gc). using direct bytebuffer
can have positive impact on code's performance.
as said, (i) won't work because don't know how data method going return. (ii) complex because of custom packaging protocol. go modified version of (iii): don't need object, can return array of bytebuffer
s first element hash , other elements thumbnails. , can throw away memcpy
s! that's entire point in direct bytebuffer
: avoiding copying.
code:
void java_myclass_createthumbnails(jnienv* env, jobject, jobject input, jobjectarray output) { jsize nthumbnails = env->getarraylength(output) - 1; void* inputptr = env->getdirectbufferaddress(input); jlong inputlength = env->getdirectbuffercapacity(input); // ... void* hash = ...; // pointer hash data int hashdatalength = ...; void** thumbnails = ...; // array of pointers, each 1 points thumbnail data int* thumbnaildatalengths = ...; // array of ints, each 1 length of thumbnail data same index jobject hashbuffer = env->newdirectbytebuffer(hash, hashdatalength); env->setobjectarrayelement(output, 0, hashbuffer); (int = 0; < nthumbnails; i++) env->setobjectarrayelement(output, + 1, env->newdirectbytebuffer(thumbnails[i], thumbnaildatalengths[i])); }
edit:
i have byte array available me input. wouldn't wrapping byte array in byte buffer still incur same tax? syntax arrays: http://developer.android.com/training/articles/perf-jni.html#region_calls. though copy still possible.
getbytearrayregion
write buffer, therefore creating copy every time, suggest getbytearrayelements
instead. copying array direct bytebuffer
on java side not best idea because still have copy avoid if getbytearrayelements
pins array.
if create byte buffers wrap native data, responsible cleaning up? did memcpy because thought java have no idea when free this. memory on stack, on heap or custom allocator, seems cause bugs.
if data on stack, must copy java array, direct bytebuffer
created in java code or somewhere on heap (and direct bytebuffer
points location). if it's on heap, can safely use direct bytebuffer
created using newdirectbytebuffer
long can ensure nobody frees memory. when heap memory free'd, must no longer use bytebuffer
object. java not try remove native memory when direct bytebuffer
created using newdirectbytebuffer
gc'd. have take care of manually, because created buffer manually.
Comments
Post a Comment