trouble passing float array from C to java method

Discussion in 'Java' started by Arash Nikkar, Feb 16, 2007.

  1. Arash Nikkar

    Arash Nikkar Guest

    I have a float array, and I am trying to pass it to a java method, but
    it craps out during the call to pass the array. Anyone have any ideas?

    Here is the header for the java method:

    public void addPoints(final float[] scopePoints)

    and here is the C++ reference to this method:

    addPoints = jenv->GetMethodID(myClass, "addPoints", "([F)V");

    lastly, here is the code in question (the printMsg function is just a
    helper function which calls a println method in my java class). Also,
    SampleData is defined as such: float SampleData[3072];

    jfloat realGraph[3000];
    printMsg("created jint array\n");
    for (i=0;i<3000;i++)
    {
    realGraph = SampleData;
    }

    printMsg("copied array\n");

    jfloatArray returnArray = jenv->NewFloatArray(3000);
    printMsg("created java jint array\n");

    jenv->SetFloatArrayRegion(returnArray,
    0,3000,realGraph);
    printMsg("transfered data into java array\n");

    jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
    WHERE IT FAILS!!!
    printMsg("passed the array\n");


    when i run the code, all of the print messages come through except the
    last one. I also added loops which printed out the contents of each
    array (SampleData, realGraph, & returnArray), and they all contain the
    correct contents.

    Any help is appreciated
     
    Arash Nikkar, Feb 16, 2007
    #1
    1. Advertising

  2. Arash Nikkar

    Chris Uppal Guest

    Arash Nikkar wrote:

    > jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
    > WHERE IT FAILS!!!
    > printMsg("passed the array\n");


    What is the value of jobj at this point ? Your code looks OK to me, so I
    suspect that jobj might not be properly set up.

    In general, it's a very bad idea to call JNI functions without checking for
    errors. That call, or any of the preceeding JNI functions might have failed,
    and once something has failed (thrown a Java exception which you haven't
    checked for), nothing else will work. If you add error checking, then that
    might help track down the problem.

    Incidentally, I think an array of 3000 floats is a little large to be
    allocating on the C stack; its not large enough that expect that it would
    routinely cause problems, but not so small that I'd ignore it either.

    -- chris
     
    Chris Uppal, Feb 16, 2007
    #2
    1. Advertising

  3. Arash Nikkar

    Arash Nikkar Guest

    On Feb 16, 11:01 am, "Chris Uppal" <-
    THIS.org> wrote:
    > Arash Nikkar wrote:
    > > jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
    > > WHERE IT FAILS!!!
    > > printMsg("passed the array\n");

    >
    > What is the value of jobj at this point ? Your code looks OK to me, so I
    > suspect that jobj might not be properly set up.
    >
    > In general, it's a very bad idea to call JNI functions without checking for
    > errors. That call, or any of the preceeding JNI functions might have failed,
    > and once something has failed (thrown a Java exception which you haven't
    > checked for), nothing else will work. If you add error checking, then that
    > might help track down the problem.
    >
    > Incidentally, I think an array of 3000 floats is a little large to be
    > allocating on the C stack; its not large enough that expect that it would
    > routinely cause problems, but not so small that I'd ignore it either.
    >
    > -- chris


    Hi chris,

    job is my jobject reference. For this application, the C code is
    running in the background and calling my Java function when it gathers
    a specific number of results.

    I tried reducing the size of my array to 500, but I got the same
    problem, the program crashed as it was sending the array to my java
    function.

    I dont quite understand what you mean by adding error checking. Im
    assuming you mean in the c++ code...what type of error checking? could
    you give me an example.

    Lastly, Im pretty sure that my jenv and job objects are setup
    correctly, as the printMsg uses them. Here is the code for my printMsg
    method:

    void printMsg(char *str) {
    jstring myString = jenv->NewStringUTF(str);
    jenv->CallVoidMethod(job, print, myString);
    }

    Thanks for all your help!
     
    Arash Nikkar, Feb 16, 2007
    #3
  4. Arash Nikkar

    Daniel Pitts Guest

    On Feb 16, 2:11 pm, "Arash Nikkar" <> wrote:
    > On Feb 16, 11:01 am, "Chris Uppal" <-
    >
    >
    >
    > THIS.org> wrote:
    > > Arash Nikkar wrote:
    > > > jenv->CallVoidMethod(job, addPoints, returnArray); //THIS IS
    > > > WHERE IT FAILS!!!
    > > > printMsg("passed the array\n");

    >
    > > What is the value of jobj at this point ? Your code looks OK to me, so I
    > > suspect that jobj might not be properly set up.

    >
    > > In general, it's a very bad idea to call JNI functions without checking for
    > > errors. That call, or any of the preceeding JNI functions might have failed,
    > > and once something has failed (thrown a Java exception which you haven't
    > > checked for), nothing else will work. If you add error checking, then that
    > > might help track down the problem.

    >
    > > Incidentally, I think an array of 3000 floats is a little large to be
    > > allocating on the C stack; its not large enough that expect that it would
    > > routinely cause problems, but not so small that I'd ignore it either.

    >
    > > -- chris

    >
    > Hi chris,
    >
    > job is my jobject reference. For this application, the C code is
    > running in the background and calling my Java function when it gathers
    > a specific number of results.
    >
    > I tried reducing the size of my array to 500, but I got the same
    > problem, the program crashed as it was sending the array to my java
    > function.
    >
    > I dont quite understand what you mean by adding error checking. Im
    > assuming you mean in the c++ code...what type of error checking? could
    > you give me an example.
    >
    > Lastly, Im pretty sure that my jenv and job objects are setup
    > correctly, as the printMsg uses them. Here is the code for my printMsg
    > method:
    >
    > void printMsg(char *str) {
    > jstring myString = jenv->NewStringUTF(str);
    > jenv->CallVoidMethod(job, print, myString);
    >
    > }
    >
    > Thanks for all your help!



    Does it crash, or simply never return? Could it be a problem in
    addPoints?
     
    Daniel Pitts, Feb 17, 2007
    #4
  5. On 16 Feb 2007 14:11:35 -0800, Arash Nikkar wrote:
    > Lastly, Im pretty sure that my jenv and job objects are setup
    > correctly, as the printMsg uses them. Here is the code for my
    > printMsg method:
    >
    > void printMsg(char *str) {
    > jstring myString = jenv->NewStringUTF(str);
    > jenv->CallVoidMethod(job, print, myString);
    > }


    Note that you should call DeleteLocalRef(myString) before returning
    from this function.

    If your C++ code is running in its own thread and producing objects
    without returning to Java (*calling* Java is not suffucient), then you
    must dispose of them when you're finished using them. Failing to do so
    is a serious bug that could very well be the cause of your current
    problem.

    Consider bracketing the code in calls to PushLocalFrame() and
    PopLocalFrame().

    /gordon

    --
    [ don't email me support questions or followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Feb 17, 2007
    #5
  6. Arash Nikkar

    Chris Uppal Guest

    Arash Nikkar wrote:

    > > What is the value of jobj at this point ? Your code looks OK to me, so
    > > I suspect that jobj might not be properly set up.


    > job is my jobject reference. For this application, the C code is
    > running in the background and calling my Java function when it gathers
    > a specific number of results.


    Just to check: the jobj is a global ref, or a local ref (jobject) from the
    JNIEnv associated with your background thread ? If not then that might be your
    problem.


    > > In general, it's a very bad idea to call JNI functions without checking
    > > for errors. That call, or any of the preceeding JNI functions might
    > > have failed, and once something has failed (thrown a Java exception
    > > which you haven't checked for), nothing else will work. If you add
    > > error checking, then that might help track down the problem.


    > I dont quite understand what you mean by adding error checking. Im
    > assuming you mean in the c++ code...what type of error checking? could
    > you give me an example.


    After every call to JNI you should check for errors (there are, in fact, a few
    JNI functions which have no way to fail, but they are in the minority -- if you
    see JNI code without an error check, then you should wonder why it's missing).



    > printMsg("created jint array\n");


    Since you've said that printMsg() uses JNI, it should check for errors too (as
    below).


    > jfloatArray returnArray = jenv->NewFloatArray(3000);


    This can fail. So you should check the returned value (it may be NULL). I'm
    not certain, but I /think/ that if the returned value is not NULL then you are
    not obliged to check for Java exceptions too. (I do anyway, myself, but that's
    in automatically-generated code so it's easier always to check than to try to
    spot the cases where a check can be skipped).


    > jenv->SetFloatArrayRegion(returnArray,
    > 0,3000,realGraph);


    You'll have to check the spec to see whether this can potentially fail. I
    don't /think/ so, but it's your responsibility to check the specification.


    > jenv->CallVoidMethod(job, addPoints, returnArray);


    This can fail by throwing a Java exception. The only way to check whether that
    happened is one of ExceptionCheck() or ExceptionOcurred(). If it did then you
    can clear it with ExceptionClear(). If you don't clear it then subsequent JNI
    calls will fail. The helper function ExceptionDescribe() may also be useful
    (but for the life of me, I can't remember whether it implicitly clears the
    pending exception).


    > void printMsg(char *str) {
    > jstring myString = jenv->NewStringUTF(str);
    > jenv->CallVoidMethod(job, print, myString);
    > }



    You should also do the same kind of messing around inside printMsg():
    NewString() can fail, and CallVoidMethod() can throw exceptions. (And you
    should release the jstring, as Gordon has already explained).


    I know that all that checking is /extremely/ tedious, and messes up the code.
    Unfortunately, it's necessary (which is one of the reasons I don't write JNI
    code by hand...).


    BTW, if you haven't already tried turning on the -Xcheck:jni option, then that
    is probably worth the effort. NB: I have known it produce false positives
    (complain about something that was perfectly OK, and abort when there was no
    need) in one dot.dot release of JDK 1.5, but it is usually helpful (of course,
    if it /doesn't/ complain then that doesn't imply that the code /is/ OK).

    -- chris
     
    Chris Uppal, Feb 17, 2007
    #6
  7. Arash Nikkar

    Arash Nikkar Guest

    Thanks for all the replies, here are some answers:

    I have made some progress (I believe I found the source of the
    problem, but I cant figure it out just yet).

    I added the Xcheck:jni runtime option, and I got the following:

    FATAL ERROR in native method: Using JNIEnv in the wrong thread
    at RealGraph.startScope(Native Method)
    at RealGraph$2.run(RealGraph.java:134)
    at java.lang.Thread.run(Thread.java:595)

    Then I realized I was calling this method from within another Java
    Thread (I didn't know this would have any type of effect). So I moved
    the call outside of the thread (i.e. it would make my GUI hang, but
    thats ok for now), but then I got this:

    FATAL ERROR in native method: Wrong object class or methodID passed to
    JNI call
    at RealGraph.startScope(Native Method)
    at RealGraph.main(RealGraph.java:124)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
    39)
    at
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
    25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:
    90)

    Some background on how I have things setup. When I first start my
    application, I call an initialization method in my C++ class which
    sets global environment variables for JENV, Jobject, and my method
    pointers (i.e. addPoints, print), etc. I also do some checks there.

    Then, when I am ready to start polling, I call the startScope method.
    Here I only perform polling operations. I do not replace my
    environment variables or method pointers. I did try this however, and
    I got the same exception as the one above.


    Lastly, for exception checking, will calls to ExceptionCheck() or
    ExceptionOcurred() suffice, or should I check for null values as well?

    thanks for all your help!
     
    Arash Nikkar, Feb 20, 2007
    #7
  8. On 20 Feb 2007 10:26:53 -0800, Arash Nikkar wrote:
    > Some background on how I have things setup. When I first start my
    > application, I call an initialization method in my C++ class which
    > sets global environment variables for JENV, Jobject, and my method
    > pointers (i.e. addPoints, print), etc. I also do some checks there.


    Don't cache the JNIEnv!

    Also, be careful when caching object references: it's only safe to
    cache global references.

    /gordon

    --
    [ don't email me support questions or followups ]
    g o r d o n + n e w s @ b a l d e r 1 3 . s e
     
    Gordon Beaton, Feb 20, 2007
    #8
  9. Arash Nikkar

    Chris Uppal Guest

    Arash Nikkar wrote:

    > Some background on how I have things setup. When I first start my
    > application, I call an initialization method in my C++ class which
    > sets global environment variables for JENV, Jobject, and my method
    > pointers (i.e. addPoints, print), etc. I also do some checks there.


    It OK to put methodIDs (method pointers) into global variables because they can
    be used from any thread, but jobjects and JNIEnvs are completely tied to the
    thread which created them and they must never be used from any other thread.

    In JNI there are three possible scenarios.

    1) (I include this case only for completeness since I don't think it applies to
    you.) The application itself is in C (or similar), and uses JNI to invoke Java
    code. In this case the C code will load and launch the JVM itself, and in
    doing so will create a JNIEnv which is valid in, and only in, that OS thread.
    Any jobjects (local references) which are created via that JNIEnv are also
    valid on that thread (and only on that thread). Note that you must release
    such references explicitly.

    2) Your C code is invoked via a Java 'native' call. In that case the Java
    runtime will supply a JNIEnv for you to use for the duration of that call.
    That JNIEnv is not valid in any other call, nor in any other thread. Any
    jobject (local reference) created during that call will be released when the
    call returns back to Java code, so the jobject is invalid anywhere else too.

    3) Your C code is running on a separate thread which the Java VM doesn't know
    about. Unless you /tell/ the JVM about that thread then no JNIEnv or jobject
    can validly be used from it. If you call the JNI function
    AttachCurrentThread() or AttachCurrentThreadAsDemon(), that tells the JVM about
    the thread from which it was called, and passes back a JNIEnv. The new JNIEnv
    is valid for use on that thread, and only on that thread. Any jobjects (local
    references) which are created via that JNIEnv are also valid on that thread
    (and only on that thread). Note that you must release such references
    explicitly.

    If you need (as I think you do) to store a reference to a specific Java object,
    and use that later from different places and threads, then you must convert it
    to a "global reference" using NewGlobalRef(). Such a global reference is valid
    in any thread. It must be released explicitly.

    Incidentally, the JNI function GetEnv() can be used to retrieve the correct
    JNIEnv to use it whatever context its called from (it'll return an error if
    called from a thread which hasn't been attached by the JVM). That function is
    (by design) very quick so it may be more convenient for you to use that instead
    of global variables.


    > Lastly, for exception checking, will calls to ExceptionCheck() or
    > ExceptionOcurred() suffice, or should I check for null values as well?


    You are asking about the call to NewFloatArray() ? If so then I believe that
    either an exception check, or a NULL check, is adequate -- you don't need to do
    both. That applies to all the array-creation methods.

    In the more general case (not just array creation) where a JNI function returns
    a jobject. I believe (but am not totally certain) that they always return NULL
    if there is any problem, so you only have to do the exception check if you see
    a NULL return. (Some of the functions can return NULL without it being an
    indication of a problem, so you can't in general use an exception check
    /instead/ of a NULL check). For instance calling this Java method, with
    CallObjectMethod(), would return NULL, but there'd be no exception pending.

    static String someMethod() { return null; }


    I think you would benefit from reading the JNI book, which can be downloaded
    from:
    http://java.sun.com/docs/books/jni/
    It's not too long, and is very helpful.

    -- chris
     
    Chris Uppal, Feb 20, 2007
    #9
  10. Arash Nikkar

    Arash Nikkar Guest

    (NOTE: This might become a repost, as I tried to post this earlier)

    Thanks to everyone for their help. I learned a couple of lessons here,
    no more global jenv/job variables, error checking & clean up after
    myself (i.e. release strings/arrays).

    I never could get the GetEnv() method to work, so instead I just pass
    the jenv/job variables between methods, that way the correct thread is
    using the correct variables.

    I have one last question: Do I need to ReleaseFloatArray if I created
    it using NewFloatArray?

    i.e.:

    jfloat realGraph[5000];

    for (i=0;i<5000;i++) {
    realGraph = SampleData;
    }

    jfloatArray returnArray = jenv->NewFloatArray(5000);

    jenv->SetFloatArrayRegion(returnArray,
    0,5000,realGraph);

    jenv->CallVoidMethod(job, addPoints, returnArray);

    do I need to release returnArray? or realGraph for that matter?

    thanks again to all who provided input!!
     
    Arash Nikkar, Feb 20, 2007
    #10
  11. Arash Nikkar

    Chris Uppal Guest

    Arash Nikkar wrote:

    > I have one last question: Do I need to ReleaseFloatArray if I created
    > it using NewFloatArray?


    There is no function called ReleaseFloatArray(). I don't /think/ you meant
    ReleaseFloatArrayElements(), but just in case you did then that is always
    paired with GetFloatArrayElements() and should not be called for any other
    reason (and always must be called after GetFloatArrayElements()).

    But I think you were asking whether you have to do a DeleteLocalRef() on the
    reference returned by NewFloatArray(). If so then the answer is that you do
    have to ensure that the reference is released. However, whether you need an
    /explicit/ call to DeleteLocalRef() depends on how and where your code is
    running. It'll never do any harm to call it yourself, but under some
    circumstances the system will do it for you. That will happen if your code has
    been called from a Java native method (as I mentioned before); or if you make
    use of PushLocalFrame() and PopLocalFrame() (as Gordon mentioned earlier) --
    see the book I recommended for details and more explanation.


    > jfloat realGraph[5000];

    [...]
    > do I need to release [...] realGraph for that matter?


    No, that's just a normal C array and is subject to normal C rules -- there's no
    special JNI magic you have to worry about.

    -- chris
     
    Chris Uppal, Feb 21, 2007
    #11
  12. Arash Nikkar

    Arash Nikkar Guest

    apparently im having problems posting to this group, because my last
    msg didn't show up.

    anywyas, I just wanted to thank you for such a thorough answer. I
    ended up adding the DeleteLocalRef call, as this function is called
    very often (its somewhat of a delayed real-time system).

    thanks again!
     
    Arash Nikkar, Feb 22, 2007
    #12
    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. Andy
    Replies:
    7
    Views:
    6,334
    Roedy Green
    May 10, 2004
  2. Jim West
    Replies:
    4
    Views:
    1,517
    Jeff Schwab
    Jan 16, 2004
  3. Jukka Lehtonen

    operator== (float, float)

    Jukka Lehtonen, Aug 4, 2004, in forum: C++
    Replies:
    5
    Views:
    2,458
    Jukka Lehtonen
    Aug 5, 2004
  4. bd
    Replies:
    0
    Views:
    673
  5. Carsten Fuchs
    Replies:
    45
    Views:
    1,660
    James Kanze
    Oct 8, 2009
Loading...

Share This Page