Keep JVM alive with JNI

Discussion in 'Java' started by Herman, May 24, 2004.

  1. Herman

    Herman Guest

    I have an application written in C that invokes a JVM and is using a
    charting package written in java. I'm writing out png files from the
    application. Everthing compiles fine and the C application will behave
    correctly the first time through. But when I come back and try it
    again it bombs with a segmentation fault. What I need to do is keep
    the JVM alive when it is intially invoked. My program is a derivation
    of the invoke.c that is in the JNI documentation on the java.sun.com
    site. I've looked at the thread example in the JNI documentation but
    I'm not sure that my application needs to multithreaded as much as it
    needs to be reentrant and the JVM should be 'kept alive'. Any help
    with this matter would be greatly appreciated.
    Herman, May 24, 2004
    #1
    1. Advertising

  2. On 24 May 2004 12:18:43 -0700, Herman wrote:
    > I have an application written in C that invokes a JVM and is using a
    > charting package written in java. I'm writing out png files from the
    > application. Everthing compiles fine and the C application will
    > behave correctly the first time through. But when I come back and
    > try it again it bombs with a segmentation fault. What I need to do
    > is keep the JVM alive when it is intially invoked.


    What exactly do you mean by "come back and try it again"? Do you start
    the C program a second time? If that causes a segmentation fault, then
    I'd be looking for errors in the code, rather than a way to avoid
    having to start it again.

    > My program is a derivation of the invoke.c that is in the JNI
    > documentation on the java.sun.com site. I've looked at the thread
    > example in the JNI documentation but I'm not sure that my
    > application needs to multithreaded as much as it needs to be
    > reentrant and the JVM should be 'kept alive'. Any help with this
    > matter would be greatly appreciated.


    You don't need to do anything special. Once you've called
    JNI_CreateJavaVM(), invoke whatever method you need to invoke. The JVM
    doesn't terminate when the method returns, so you can invoke another
    method later (in the same JVM) if you like. There's absolutely nothing
    special you need to do.

    Your description is rather vague, so it's difficult to give more
    specific advice. Post a short, relevant code example.

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
    Gordon Beaton, May 24, 2004
    #2
    1. Advertising

  3. Herman

    Herman Guest

    Gordon Beaton <> wrote in message news:<40b25218$>...
    > On 24 May 2004 12:18:43 -0700, Herman wrote:
    > > I have an application written in C that invokes a JVM and is using a
    > > charting package written in java. I'm writing out png files from the
    > > application. Everthing compiles fine and the C application will
    > > behave correctly the first time through. But when I come back and
    > > try it again it bombs with a segmentation fault. What I need to do
    > > is keep the JVM alive when it is intially invoked.

    >
    > What exactly do you mean by "come back and try it again"? Do you start
    > the C program a second time? If that causes a segmentation fault, then
    > I'd be looking for errors in the code, rather than a way to avoid
    > having to start it again.
    >
    > > My program is a derivation of the invoke.c that is in the JNI
    > > documentation on the java.sun.com site. I've looked at the thread
    > > example in the JNI documentation but I'm not sure that my
    > > application needs to multithreaded as much as it needs to be
    > > reentrant and the JVM should be 'kept alive'. Any help with this
    > > matter would be greatly appreciated.

    >
    > You don't need to do anything special. Once you've called
    > JNI_CreateJavaVM(), invoke whatever method you need to invoke. The JVM
    > doesn't terminate when the method returns, so you can invoke another
    > method later (in the same JVM) if you like. There's absolutely nothing
    > special you need to do.
    >
    > Your description is rather vague, so it's difficult to give more
    > specific advice. Post a short, relevant code example.
    >
    > /gordon


    Sorry for the vagueness. Here is a code snippet:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <jni.h>
    #include "idscharts.h"

    #define USER_CLASSPATH ".";


    JavaVM *jvm;
    static jint res = -1;
    JNIEnv *env;
    static jclass cls;
    static jmethodID mid;

    int chartsX(CChartData *chartData,
    CChartProps chartProps,
    int numElements,
    char *javaHome,
    char *display,
    char *chartWrapper,
    char *pja,
    char *jPowered)
    {

    jfieldID width, height, fname, type;

    jstring jstr;
    jclass stringClass, doubleClass;
    jobjectArray segLabels, segValues;

    int i;
    char* label, element;
    static char jarfiles[255] = "";
    char classpath[255] = "-Djava.class.path=";
    static char value[1024];
    char* position;
    int index;
    static char* jh;



    char javafont[100] = "-Djava.awt.fonts=";
    char bootclasspath[100] = "-Xbootclasspath/a:";
    static char pjadir[100];
    char search_char = '/';

    jh = javaHome;


    /* cut off filename from directory. used for user.home JVM option */
    position = strrchr(pja, '/');
    index = pja - position;

    if (index < 0 )
    index *= -1;

    strncpy(pjadir, pja, index);


    strcat(jarfiles, chartWrapper);
    strcat(jarfiles, ":");
    strcat(jarfiles, jPowered);
    strcat(classpath, jarfiles);



    /* append the directory and filename to java -xbootclasspath
    directive */
    strcat(bootclasspath, pja);



    /* Make string of where java fonts reside */
    strcat(jh,"/lib/fonts");
    strcat(javafont, jh);



    #ifdef JNI_VERSION_1_4
    JavaVMInitArgs vm_args;
    JavaVMOption options[10];
    options[0].optionString =
    "-Djava.awt.headless=false";
    options[1].optionString = bootclasspath;
    options[2].optionString = "-Xms256m"; /* convert to variable if needs
    to be dynamically adjusted */
    options[3].optionString = "-Xmx512m";
    options[4].optionString =
    "-Dawt.toolkit=com.eteks.awt.PJAToolkit";
    options[5].optionString =
    "-Djava.awt.graphics=com.eteks.PJAGraphicEnvironment";
    options[6].optionString =
    "-Djava2d.font.usePlatformFont=false";
    options[7].optionString = javafont;
    options[8].optionString = pjadir;
    options[9].optionString = classpath;
    vm_args.version = 0x00010004;
    vm_args.options = options;
    vm_args.nOptions = 10;
    vm_args.ignoreUnrecognized = JNI_TRUE;
    /* Create the Java VM */


    if (res < 0 ) {
    res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    }
    else
    {
    res = (*jvm)->AttachCurrentThread(jvm, (void**)&env, NULL);
    }

    #else
    JDK1_1InitArgs vm_args;
    char classpath[1024];
    vm_args.version = 0x00010001;
    JNI_GetDefaultJavaVMInitArgs(&vm_args);
    /* Append USER_CLASSPATH to the default system class path */
    sprintf(classpath, "%s%c%s",
    vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
    vm_args.classpath = classpath;
    /* Create the Java VM */
    res = JNI_CreateJavaVM(&jvm, &env, &vm_args);
    #endif /* JNI_VERSION_1_2 */


    if (res < 0) {
    fprintf(stderr, "Can't create Java VM\n");
    exit(1);
    }

    cls = (*env)->FindClass(env, "ChartWrapper");
    if (cls == NULL) {
    goto destroy;
    }
    cls = (*env)->NewWeakGlobalRef(env, cls);
    /*DeleteLocalRef(cls); */


    mid = (*env)->GetMethodID(env, cls, "setChartSettings",
    "([Ljava/lang/String;[Ljava/lang/String;)V");
    if (mid == NULL) {
    goto destroy;
    }

    width = (*env)->GetFieldID(env, cls, "WIDTH", "I");
    if (width == NULL) {
    printf("Width - Didn't get it\n");
    }
    (*env)->SetIntField(env, cls, width, chartProps.width);


    height = (*env)->GetFieldID(env, cls, "HEIGHT", "I");
    if (height == NULL) {
    goto destroy;
    }
    (*env)->SetIntField(env, cls, height, chartProps.height);

    type = (*env)->GetFieldID(env, cls, "chartType", "I");
    if (height == NULL) {
    goto destroy;
    }
    (*env)->SetIntField(env, cls, type, chartProps.chartType);


    stringClass = (*env)->FindClass(env, "java/lang/String");
    jstr = (*env)->NewStringUTF(env, " ");

    segLabels = (*env)->NewObjectArray (env, numElements ,
    (*env)->FindClass(env, "java/lang/String"),jstr);


    segValues = (*env)->NewObjectArray (env, numElements ,
    (*env)->FindClass(env, "java/lang/String"),jstr);

    for (i = 0; i < numElements; i++) {

    label = chartData.label;
    jstr = (*env)->NewStringUTF(env, label);
    sprintf(value, "%01.2f", chartData.value);
    (*env)->SetObjectArrayElement(env, segLabels, i, jstr);
    jstr = (*env)->NewStringUTF(env, value);
    (*env)->SetObjectArrayElement(env, segValues, i, jstr);
    }


    fname = (*env)->GetFieldID(env, cls, "chartFileName",
    "Ljava/lang/String;");
    if (fname == NULL) {
    goto destroy;
    }

    jstr = (*env)->NewStringUTF(env, chartProps.filename);

    (*env)->SetObjectField(env, cls, fname, jstr);

    (*env)->CallVoidMethod(env, cls, mid, segLabels, segValues);

    return 0;

    destroy:
    if ((*env)->ExceptionOccurred(env)) {
    (*env)->ExceptionDescribe(env);
    }
    (*jvm)->DestroyJavaVM(jvm);
    }

    void destroyJVM() {
    (*jvm)->DestroyJavaVM(jvm);
    }

    What I'm trying to do is keep the JVM and the ChartWrapper class
    persistent so that the JVM doesn't have to be intialized again when
    the chartX method is called again. This program is built as a shared
    object and the chartX method is called by a c application. So
    basically it is c calling java. Hopefully this is a bit clearer.
    Thanks for any advice you can lend.
    Herman, May 25, 2004
    #3
  4. Herman

    Herman Guest

    Gordon Beaton <> wrote in message news:<40b25218$>...
    > On 24 May 2004 12:18:43 -0700, Herman wrote:
    > > I have an application written in C that invokes a JVM and is using a
    > > charting package written in java. I'm writing out png files from the
    > > application. Everthing compiles fine and the C application will
    > > behave correctly the first time through. But when I come back and
    > > try it again it bombs with a segmentation fault. What I need to do
    > > is keep the JVM alive when it is intially invoked.

    >
    > What exactly do you mean by "come back and try it again"? Do you start
    > the C program a second time? If that causes a segmentation fault, then
    > I'd be looking for errors in the code, rather than a way to avoid
    > having to start it again.
    >
    > > My program is a derivation of the invoke.c that is in the JNI
    > > documentation on the java.sun.com site. I've looked at the thread
    > > example in the JNI documentation but I'm not sure that my
    > > application needs to multithreaded as much as it needs to be
    > > reentrant and the JVM should be 'kept alive'. Any help with this
    > > matter would be greatly appreciated.

    >
    > You don't need to do anything special. Once you've called
    > JNI_CreateJavaVM(), invoke whatever method you need to invoke. The JVM
    > doesn't terminate when the method returns, so you can invoke another
    > method later (in the same JVM) if you like. There's absolutely nothing
    > special you need to do.
    >
    > Your description is rather vague, so it's difficult to give more
    > specific advice. Post a short, relevant code example.
    >
    > /gordon


    The same method chartX will be called over and over. What seems to
    happen is that tbe program bombs when called again.
    Herman, May 25, 2004
    #4
  5. On 25 May 2004 08:28:34 -0700, Herman wrote:
    > The same method chartX will be called over and over. What seems to
    > happen is that tbe program bombs when called again.


    Ok after looking at your code I can see what you are trying to do:

    int chartX()
    {
    if (!jvm) {
    start jvm
    }
    else {
    AttachCurrentThread();
    }

    invoke(setChartSettings(someValues));

    return 0;
    }

    First, I wonder if one of your method calls has failed and you have
    invoked DestroyJavaVM() before returning, or if the caller has invoked
    destroy_JVM()?

    I don't think DestroyJavaVM() actually works, at any rate I have never
    been successful in starting a second JVM within the same process.
    Judging from similar questions in this and related newsgroups over the
    years, I don't think anyone else has either (although I could be
    mistaken). That is the first place I'd look.

    Second, there may be some issues with references accumulating in the
    calling scope. Normally, when calling from Java to C, any references
    returned to C automatically become eligible for GC when the C method
    returns. In your case, chartsX() is not called within the scope of a
    JVM (the relationship is the opposite) so all of your references stay
    alive even after the function returns. You need to manage all of the
    references yourself with DeleteLocalRef() before returning. For that
    reason, I don't think it's a good idea to make repeated calls to
    FindClass("java/lang/String"), for example. The same is true of all of
    the label and value Strings you create in the loop, as well as the
    ObjectArray.

    I'd suggest that you first try invoking a simple static method that
    doesn't require you to create any objects on each call, in order to
    eliminate those issues from the equation. Make sure you are able to
    invoke methods on the JVM the second and subsequent times, then
    replace that method call with your call to setChartSettings().

    Some additional points...

    - calling DestroyJavaVM() doesn't change the value of res, which you
    use to test whether to start the JVM next time. In fact I'd base the
    test on the value of the jvm pointer itself, not res. Make sure you
    set jvm to NULL after calling DestroyJavaVM() so that the second
    call to your function doesn't attempt to invoke a method on a
    non-existant JVM. But again, I don't think you can rely on
    restarting the JVM after DestroyJavaVM() has been called.

    - much of the code prior to starting the JVM is done on every call to
    chartsX(), but is only necessary when you actually invoke
    JNI_CreateJavaVM() the first time. Put all of that code inside the
    conditional block. Or preferably, break it into a separate function
    to start the JVM. Just test jvm in chartsX() and invoke the function
    if necesary. Several of the currently global variables should be
    local to that function.

    - are you sure that the character arrays jarfiles, classpath,
    javafont, bootclasspath, pjadir etc, are long enough to contain the
    data you write to them? Perhaps you are overwriting the bounds of
    one of these.

    - it is a lot easier to get and set values via method arguments than
    through reflection. Consider adding one or more helper methods to
    ChartWrapper so you don't need to make all those calls to
    GetFieldID() and SetXXField(),
    e.g. setChartProps(name, type, width, height).

    /gordon

    --
    [ do not email me copies of your followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
    Gordon Beaton, May 25, 2004
    #5
  6. Herman

    Herman Guest

    Gordon Beaton <> wrote in message news:<40b373e7$>...
    > On 25 May 2004 08:28:34 -0700, Herman wrote:
    > > The same method chartX will be called over and over. What seems to
    > > happen is that tbe program bombs when called again.

    >
    > Ok after looking at your code I can see what you are trying to do:
    >
    > int chartX()
    > {
    > if (!jvm) {
    > start jvm
    > }
    > else {
    > AttachCurrentThread();
    > }
    >
    > invoke(setChartSettings(someValues));
    >
    > return 0;
    > }
    >
    > First, I wonder if one of your method calls has failed and you have
    > invoked DestroyJavaVM() before returning, or if the caller has invoked
    > destroy_JVM()?
    >
    > I don't think DestroyJavaVM() actually works, at any rate I have never
    > been successful in starting a second JVM within the same process.
    > Judging from similar questions in this and related newsgroups over the
    > years, I don't think anyone else has either (although I could be
    > mistaken). That is the first place I'd look.
    >
    > Second, there may be some issues with references accumulating in the
    > calling scope. Normally, when calling from Java to C, any references
    > returned to C automatically become eligible for GC when the C method
    > returns. In your case, chartsX() is not called within the scope of a
    > JVM (the relationship is the opposite) so all of your references stay
    > alive even after the function returns. You need to manage all of the
    > references yourself with DeleteLocalRef() before returning. For that
    > reason, I don't think it's a good idea to make repeated calls to
    > FindClass("java/lang/String"), for example. The same is true of all of
    > the label and value Strings you create in the loop, as well as the
    > ObjectArray.
    >
    > I'd suggest that you first try invoking a simple static method that
    > doesn't require you to create any objects on each call, in order to
    > eliminate those issues from the equation. Make sure you are able to
    > invoke methods on the JVM the second and subsequent times, then
    > replace that method call with your call to setChartSettings().
    >
    > Some additional points...
    >
    > - calling DestroyJavaVM() doesn't change the value of res, which you
    > use to test whether to start the JVM next time. In fact I'd base the
    > test on the value of the jvm pointer itself, not res. Make sure you
    > set jvm to NULL after calling DestroyJavaVM() so that the second
    > call to your function doesn't attempt to invoke a method on a
    > non-existant JVM. But again, I don't think you can rely on
    > restarting the JVM after DestroyJavaVM() has been called.
    >
    > - much of the code prior to starting the JVM is done on every call to
    > chartsX(), but is only necessary when you actually invoke
    > JNI_CreateJavaVM() the first time. Put all of that code inside the
    > conditional block. Or preferably, break it into a separate function
    > to start the JVM. Just test jvm in chartsX() and invoke the function
    > if necesary. Several of the currently global variables should be
    > local to that function.
    >
    > - are you sure that the character arrays jarfiles, classpath,
    > javafont, bootclasspath, pjadir etc, are long enough to contain the
    > data you write to them? Perhaps you are overwriting the bounds of
    > one of these.
    >
    > - it is a lot easier to get and set values via method arguments than
    > through reflection. Consider adding one or more helper methods to
    > ChartWrapper so you don't need to make all those calls to
    > GetFieldID() and SetXXField(),
    > e.g. setChartProps(name, type, width, height).
    >
    > /gordon


    Good suggestions - Thanks.

    Now I've made the following changes - here is the code snippet ..

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <jni.h>
    #include "idscharts.h"

    #define USER_CLASSPATH ".";

    void destroyJVM();
    int invokeJVM(char* bootclasspath, char* javafont, char* pjadir, char*
    classpath);
    void doChart(CChartData *chartData, CChartProps chartProps, int
    numElements);
    void cleanup(jstring jstr,jobjectArray segLabels,jobjectArray
    segValues);

    JavaVM *jvm;
    JNIEnv *env;
    jclass Global_cls;

    /* Cache variables, method ids and field ids */
    static jmethodID mid;
    static jfieldID width;
    static jfieldID height;
    static jfieldID fname;
    static jfieldID type;
    static jclass stringClass;

    int chartsX(CChartData *chartData,
    CChartProps chartProps,
    int numElements,
    char *javaHome,
    char *display,
    char *chartWrapper,
    char *pja,
    char *jPowered)
    {
    char jarfiles[255] = "";
    char classpath[1024] = "-Djava.class.path=";
    char* jh;
    char* position;
    char javafont[255] = "-Djava.awt.fonts=";
    char bootclasspath[255] = "-Xbootclasspath/a:";
    char pjadir[255];
    char search_char = '/';
    int index, result;

    puts("In top of code");

    printf("The pja file: %s\n", pja);

    jh = javaHome;


    /* cut off filename from directory. used for user.home JVM option */
    position = strrchr(pja, '/');
    index = pja - position;

    if (index < 0 )
    index *= -1;

    printf("This is the position: %d\n", index);
    strncpy(pjadir, pja, index);

    printf("%s\n", pja);
    printf("%s\n", pjadir);

    strcat(jarfiles, chartWrapper);
    strcat(jarfiles, ":");
    strcat(jarfiles, jPowered);
    strcat(classpath, jarfiles);

    /*printf("in the so file\n");*/
    printf("%s\n", classpath);


    /* append the directory and filename to java -xbootclasspath
    directive */
    strcat(bootclasspath, pja);

    printf("%s\n", pjadir);


    /* Make string of where java fonts reside */
    strcat(jh,"/lib/fonts");
    puts(jh);
    strcat(javafont, jh);
    printf("%s\n", javafont);

    /* Test to see if the VM is alive */
    result = invokeJVM(bootclasspath, javafont, pjadir, classpath);

    if ( result < 0 )
    {
    destroyJVM();
    }
    else
    {
    doChart(chartData, chartProps, numElements);
    }

    return result;
    }


    int invokeJVM(char* bootclasspath,
    char* javafont,
    char* pjadir,
    char* classpath)
    {
    static jint res;

    if(!jvm) {
    puts("No active VM ...");

    #ifdef JNI_VERSION_1_4
    JavaVMInitArgs vm_args;
    JavaVMOption options[10];

    options[0].optionString =
    "-Djava.awt.headless=false";
    options[1].optionString = bootclasspath;
    options[2].optionString = "-Xms256m"; /* convert to variable if
    needs to be dynamically adjusted */
    options[3].optionString = "-Xmx512m";
    options[4].optionString =
    "-Dawt.toolkit=com.eteks.awt.PJAToolkit";
    options[5].optionString =
    "-Djava.awt.graphics=com.eteks.PJAGraphicEnvironment";
    options[6].optionString =
    "-Djava2d.font.usePlatformFont=false";
    options[7].optionString = javafont;
    options[8].optionString = pjadir;
    options[9].optionString = classpath;
    vm_args.version = 0x00010004;
    vm_args.options = options;
    vm_args.nOptions = 10;
    vm_args.ignoreUnrecognized = JNI_TRUE;
    /* Create the Java VM */
    printf("%s\n", "Trying to create VM ...");
    res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    #else
    JDK1_1InitArgs vm_args;
    char classpath[1024];

    vm_args.version = 0x00010001;
    JNI_GetDefaultJavaVMInitArgs(&vm_args);
    /* Append USER_CLASSPATH to the default system class path */
    sprintf(classpath, "%s%c%s",
    vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH);
    vm_args.classpath = classpath;
    /* Create the Java VM */
    res = JNI_CreateJavaVM(&jvm, &env, &vm_args);
    #endif /* JNI_VERSION_1_2 */

    printf(" In .so chart function \n");

    if (res < 0) {
    fprintf(stderr, "Can't create Java VM\n");
    exit(1);
    }
    }
    else
    {
    puts("VM Active ...");
    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
    }
    return res;
    }


    void doChart(CChartData *chartData,
    CChartProps chartProps,
    int numElements)
    {
    jstring jstr;
    jobjectArray segLabels;
    jobjectArray segValues;
    char* label;
    char* element;
    char value[1024];

    static jclass cls;

    int i;

    if (!Global_cls) {
    cls = (*env)->FindClass(env, "ChartWrapper");
    if (cls == NULL) {
    goto destroy;
    }
    printf("Class exists\n");

    /* Use weak global ref to allow C class to be unloaded */
    Global_cls = (*env)->NewWeakGlobalRef(env, cls);
    if (Global_cls== NULL) {
    printf("%d\n", JNI_ERR);
    }
    (*env)->DeleteLocalRef(env, cls);
    }

    if (!mid) {
    mid = (*env)->GetMethodID(env, Global_cls,
    "setChartSettings", "([Ljava/lang/String;[Ljava/lang/String;)V");
    if (mid == NULL) {
    goto destroy;
    }
    printf("setChartSettings() Method exist\n");

    width = (*env)->GetFieldID(env, Global_cls, "WIDTH", "I");
    if (width == NULL) {
    printf("Width - Didn't get it\n");
    }

    height = (*env)->GetFieldID(env, Global_cls, "HEIGHT", "I");
    if (height == NULL) {
    printf("Height - Didn't get it\n");
    }

    type = (*env)->GetFieldID(env, Global_cls, "chartType", "I");
    if (height == NULL) {
    printf("Type - Didn't get it\n");
    }

    stringClass = (*env)->FindClass(env, "java/lang/String");
    }

    jstr = (*env)->NewStringUTF(env, " ");


    /* Set individual fields in class. May change this implementation...
    */
    (*env)->SetIntField(env, Global_cls, width, chartProps.width);
    (*env)->SetIntField(env, Global_cls, height, chartProps.height);
    (*env)->SetIntField(env, Global_cls, type, chartProps.chartType);


    segLabels = (*env)->NewObjectArray (env, numElements ,stringClass,
    jstr);
    segValues = (*env)->NewObjectArray (env, numElements ,stringClass,
    jstr);

    for (i = 0; i < numElements; i++) {
    label = chartData.label;
    jstr = (*env)->NewStringUTF(env, label);
    sprintf(value, "%01.2f", chartData.value);
    (*env)->SetObjectArrayElement(env, segLabels, i, jstr);
    jstr = (*env)->NewStringUTF(env, value);
    (*env)->SetObjectArrayElement(env, segValues, i, jstr);
    }


    fname = (*env)->GetFieldID(env, Global_cls, "chartFileName",
    "Ljava/lang/String;");
    if (fname == NULL) {
    printf("filename - Didn't get it\n");
    }
    /*puts(chartProps.filename);*/

    jstr = (*env)->NewStringUTF(env, chartProps.filename);

    /*printf("Try to assign filename\n");*/
    (*env)->SetObjectField(env, Global_cls, fname, jstr);

    (*env)->CallVoidMethod(env, Global_cls, mid, segLabels,
    segValues);

    /* Try to cleanup after ourselves*/
    cleanup(width, height, fname, type, jstr, segLabels, segValues);

    destroy:
    if ((*env)->ExceptionOccurred(env)) {
    (*env)->ExceptionDescribe(env);
    }
    //(*jvm)->DestroyJavaVM(jvm);
    }

    void cleanup(jstring jstr,jobjectArray segLabels,jobjectArray
    segValues)
    {
    (*env)->DeleteLocalRef(env, jstr);
    (*env)->DeleteLocalRef(env, segLabels);
    (*env)->DeleteLocalRef(env, segValues);

    }


    void destroyJVM() {
    (*jvm)->DestroyJavaVM(jvm);
    }

    I'm going to add the helper methods as you suggested. Obviously it's
    not in the listing above.

    What's happening now is it locating the VM, but it crashes after the
    second time through. Probably still not releasing all necessary
    resources??

    One thing that might be a problem is the for loop; I'm getting the
    values of the elements from a C structure and an array of structs, so
    I think I'm going to have to use some kind of loop. I then pass two
    String Arrays to java that will populate a Vector. If there is a
    better way of accomplishing this, please enlighten me.

    Thanks in advanced
    Herman, May 27, 2004
    #6
  7. Herman

    Herman Guest

    Gordon Beaton <> wrote in message news:<40b373e7$>...
    > On 25 May 2004 08:28:34 -0700, Herman wrote:
    > > The same method chartX will be called over and over. What seems to
    > > happen is that tbe program bombs when called again.

    >
    > Ok after looking at your code I can see what you are trying to do:
    >
    > int chartX()
    > {
    > if (!jvm) {
    > start jvm
    > }
    > else {
    > AttachCurrentThread();
    > }
    >
    > invoke(setChartSettings(someValues));
    >
    > return 0;
    > }
    >
    > First, I wonder if one of your method calls has failed and you have
    > invoked DestroyJavaVM() before returning, or if the caller has invoked
    > destroy_JVM()?
    >
    > I don't think DestroyJavaVM() actually works, at any rate I have never
    > been successful in starting a second JVM within the same process.
    > Judging from similar questions in this and related newsgroups over the
    > years, I don't think anyone else has either (although I could be
    > mistaken). That is the first place I'd look.
    >
    > Second, there may be some issues with references accumulating in the
    > calling scope. Normally, when calling from Java to C, any references
    > returned to C automatically become eligible for GC when the C method
    > returns. In your case, chartsX() is not called within the scope of a
    > JVM (the relationship is the opposite) so all of your references stay
    > alive even after the function returns. You need to manage all of the
    > references yourself with DeleteLocalRef() before returning. For that
    > reason, I don't think it's a good idea to make repeated calls to
    > FindClass("java/lang/String"), for example. The same is true of all of
    > the label and value Strings you create in the loop, as well as the
    > ObjectArray.
    >
    > I'd suggest that you first try invoking a simple static method that
    > doesn't require you to create any objects on each call, in order to
    > eliminate those issues from the equation. Make sure you are able to
    > invoke methods on the JVM the second and subsequent times, then
    > replace that method call with your call to setChartSettings().
    >
    > Some additional points...
    >
    > - calling DestroyJavaVM() doesn't change the value of res, which you
    > use to test whether to start the JVM next time. In fact I'd base the
    > test on the value of the jvm pointer itself, not res. Make sure you
    > set jvm to NULL after calling DestroyJavaVM() so that the second
    > call to your function doesn't attempt to invoke a method on a
    > non-existant JVM. But again, I don't think you can rely on
    > restarting the JVM after DestroyJavaVM() has been called.
    >
    > - much of the code prior to starting the JVM is done on every call to
    > chartsX(), but is only necessary when you actually invoke
    > JNI_CreateJavaVM() the first time. Put all of that code inside the
    > conditional block. Or preferably, break it into a separate function
    > to start the JVM. Just test jvm in chartsX() and invoke the function
    > if necesary. Several of the currently global variables should be
    > local to that function.
    >
    > - are you sure that the character arrays jarfiles, classpath,
    > javafont, bootclasspath, pjadir etc, are long enough to contain the
    > data you write to them? Perhaps you are overwriting the bounds of
    > one of these.
    >
    > - it is a lot easier to get and set values via method arguments than
    > through reflection. Consider adding one or more helper methods to
    > ChartWrapper so you don't need to make all those calls to
    > GetFieldID() and SetXXField(),
    > e.g. setChartProps(name, type, width, height).
    >
    > /gordon



    It seems like its doesn't know what to do after attaching to the
    thread and it core dumps.
    Herman, May 27, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Luiz Alberto Gibson da Costa

    web chat development, http header connection: keep-alive

    Luiz Alberto Gibson da Costa, Aug 6, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    592
    Luiz Alberto Gibson da Costa
    Aug 6, 2003
  2. twscott
    Replies:
    1
    Views:
    5,016
  3. Naresh Agarwal
    Replies:
    1
    Views:
    1,022
    ExGuardianReader
    May 29, 2004
  4. Replies:
    1
    Views:
    5,855
    Thomas Weidenfeller
    Jul 11, 2005
  5. hisan
    Replies:
    1
    Views:
    1,288
    Dan Stromberg
    Jun 25, 2012
Loading...

Share This Page