Re: Can't allocate large char array in JNI
Hi Gordon,
Sorry for the lack of details. Here's the full code:
// start here
jobject new0(JNIEnv *env, jclass cls) {
jmethodID constructor_mid = (*env)->GetMethodID(env, cls,
"<init>", "()V");
if (constructor_mid == NULL) {
return NULL;
}
return (*env)->NewObject(env, cls, constructor_mid);
}
void set_int(JNIEnv *env, jclass cls, jobject obj,
char *field_name, jint value) {
jfieldID int_fid = (*env)->GetFieldID(env, cls, field_name, "I");
if (int_fid == NULL) {
return;
}
(*env)->SetIntField(env, obj, int_fid, value);
}
void set_char_array(JNIEnv *env, jclass cls, jobject obj,
char *field_name, jchar *value, int length) {
jfieldID char_array_fid = (*env)->GetFieldID(env, cls, field_name,
"[C");
if (char_array_fid == NULL) {
return;
}
jcharArray jchar_array = (*env)->NewCharArray(env, length);
if (jchar_array == NULL) {
return;
}
(*env)->SetCharArrayRegion(env, jchar_array, 0, length, value);
(*env)->ExceptionDescribe(env);
(*env)->SetObjectField(env, obj, char_array_fid, jchar_array);
}
JNIEXPORT jobject JNICALL Java_OpenCv_loadImage(JNIEnv *env, jclass
jclazz,
jstring jfilePath) {
const char *file_path = (*env)->GetStringUTFChars(env, jfilePath,
NULL);
IplImage *cv_image = cvLoadImage(file_path, CV_LOAD_IMAGE_COLOR);
(*env)->ReleaseStringUTFChars(env, jfilePath, file_path);
if (cv_image == NULL) {
return NULL;
}
jclass iplimage_cls = (*env)->FindClass(env, "IplImage");
if (iplimage_cls == NULL) {
return NULL;
}
jobject jiplimage = new0(env, iplimage_cls);
if (jiplimage == NULL) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage,
"nChannels", (jint) cv_image->nChannels);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage, "depth", (jint) cv_image-
depth);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage, "width", (jint) cv_image-
width);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage, "height", (jint) cv_image-
height);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_char_array(env, iplimage_cls, jiplimage, "imageData",
(jchar *) cv_image->imageData, cv_image->imageSize);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage,
"dataOrder", (jint) cv_image->dataOrder);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage, "origin", (jint) cv_image-
origin);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage,
"widthStep", (jint) cv_image->widthStep);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_int(env, iplimage_cls, jiplimage,
"imageSize", (jint) cv_image->imageSize);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
set_char_array(env, iplimage_cls, jiplimage, "imageDataOrigin",
(jchar *) cv_image->imageDataOrigin,
cv_image->width * cv_image->height * cv_image->nChannels);
set_int(env, iplimage_cls, jiplimage, "align", (jint) cv_image-
align);
if ((*env)->ExceptionCheck(env)) {
return NULL;
}
cvReleaseImage(&cv_image);
return jiplimage;
}
// end here
The jchar *value comes from the object allocated by the library
OpenCV, ant its size is the imageSize field of the IplImage struct.
When I run this function passing a small image, it always works; with
a medium image, it works sometimes (I run once and it works, I run
again and it doesn't!); but with a large image (specifically,
imageSize = 1434600), it never worked: the JVM crashes right on the
SetCharArrayRegion call, so the ExceptionDescribe in the line below is
never reached. So, based on this randomness I suppose the problem is
memory related, I don't know ;/
The header of the JVM crash log is this:
#
# An unexpected error has been detected by Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00002ae7f37b1cc7, pid=16200, tid=1076017488
#
# Java VM: Java HotSpot(TM) 64-Bit Server VM (10.0-b22 mixed mode
linux-amd64)
# Problematic frame:
# C [libc.so.6+0x75cc7] memcpy+0x3f7
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#
The purpose of this function, by the way, is to convert a C structure
(IplImage) to a Java object with the same attributes so it can be
parsed on the Java side.
Thanks again!
On Apr 21, 4:12 am, Gordon Beaton <n....@for.email> wrote:
On Sun, 20 Apr 2008 20:07:48 -0700 (PDT), CD1 wrote:
My code is like this:
Code that's "like" yours doesn't help anyone debug your real code.
// the variables are JNIEnv *env, int length, jchar *value, jmethodID
char_array_fid
jcharArray jchar_array = (*env)->NewCharArray(env, length);
if (jchar_array == NULL) {
return;
}
(*env)->SetCharArrayRegion(env, jchar_array, 0, length, value); // !!!
(*env)->SetObjectField(env, obj, char_array_fid, jchar_array);
By using printfs, I've found out the JVM crashes when it calls the
function SetCharArrayRegion, but only if the length is greater than
718832. And if I modify the length value to something like 1000, this
exact code works fine.
Any help would be appreciated :)
Try posting a compilable example or at least a complete function. The
problem is usually in the parts you didn't post.
How many jchars are in the "jchar *value" array that you pass to
SetCharArrayRegion? Perhaps more importantly, how did you allocate and
initialize it?
What does (*env)->ExceptionOccurred(env) (and ExceptionDescribe()) say
after the call to SetCharArrayRegion()? After SetObjectField()?
/gordon
--