Re: OutOfMemoryError when allocating memory via JNI

614 views
Skip to first unread message

David Turner

unread,
Mar 12, 2013, 11:33:40 PM3/12/13
to andro...@googlegroups.com
The simplest explanation is that you still have references to the object that you forgot to free.
I had a quick look at your code, and it looks like you never free the local inputStream local reference created in AndroidFileSystem::Open() and passed to the AndroidFDStream() constructor. That could easily explain your problem.

However, I had only a quick look at the code, I wouldn't be surprised if other errors are present in it (or that I missed an important detail).

If you're using C++, you should really consider using custom scoped JNI reference types with pass / release semantics, they would make this kind of error much less frequent.

On Tue, Mar 12, 2013 at 3:13 AM, <bell...@gmail.com> wrote:
I'm not sure what I'm doing wrong. Basically I'm making a bunch of calls to NewByteArray(), putting the result in a call to NewGlobalRef(), and then later calling DeleteGlobalRef(). That's exactly what I should be doing, right? Because for some reason I am still getting out of memory errors. I've been looking at the logs of my app as it runs, and I see things like this:

GC_FOR_ALLOC freed <1K, 2% free 14659K/14836K, paused 32ms, total 32ms

But that doesn't make sense to me. Why was it only about to free <1K when a moment earlier I had just called DeleteGlobalRef() on a byte array that was hundreds of KB? It's like the calls to DeleteGlobalRef() have no effect.

If anyone wants to look at some code, it's here. AndroidFileStream is the relevant class.

Any ideas?

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-ndk...@googlegroups.com.
To post to this group, send email to andro...@googlegroups.com.
Visit this group at http://groups.google.com/group/android-ndk?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

bell...@gmail.com

unread,
Mar 13, 2013, 10:48:29 AM3/13/13
to andro...@googlegroups.com
So I still need to call DeleteLocalRef() on the inputStream reference, even though I'm creating a global reference from it and deleting that later on?

When you say, "custom scoped JNI reference types with pass / release semantics," are you talking about something like std::unique_ptr<>, except that automatically calls Delete___Ref() when it goes out of scope?

RichardC

unread,
Mar 13, 2013, 2:00:49 PM3/13/13
to andro...@googlegroups.com
If you don't delete the local ref, then you have 2 refs on the object after you create the global ref until you return into Java when all local refs are released for you.


When you say, "custom scoped JNI reference types with pass / release semantics," are you talking about something like std::unique_ptr<>, except that automatically calls Delete___Ref() when it goes out of scope?

Yes 

bell...@gmail.com

unread,
Mar 13, 2013, 10:22:24 PM3/13/13
to andro...@googlegroups.com
Thanks, guys! That seems to have been exactly what was wrong. I added some DeleteLocalRef()s and the problem went away.

gadget

unread,
Mar 14, 2013, 12:13:21 AM3/14/13
to andro...@googlegroups.com
you usually don't have to delete local refs, unless.... you make so many of them, that it triggers one of dalvik's exceptions. An example of this would be doing something like NewStringUTF in a loop. Allocating too much "java" memory, or creating too many locals (512 in dalvik, and something like 16 in java) will be a problem.

David Turner

unread,
Mar 14, 2013, 9:15:56 AM3/14/13
to andro...@googlegroups.com
On Wed, Mar 13, 2013 at 3:48 PM, <bell...@gmail.com> wrote:
So I still need to call DeleteLocalRef() on the inputStream reference, even though I'm creating a global reference from it and deleting that later on?

When you say, "custom scoped JNI reference types with pass / release semantics," are you talking about something like std::unique_ptr<>, except that automatically calls Delete___Ref() when it goes out of scope?

Yes, that's exactly that kind of thing :-)


David Turner

unread,
Mar 14, 2013, 9:18:05 AM3/14/13
to andro...@googlegroups.com
On Thu, Mar 14, 2013 at 5:13 AM, gadget <avraz...@gmail.com> wrote:
you usually don't have to delete local refs, unless.... you make so many of them, that it triggers one of dalvik's exceptions. An example of this would be doing something like NewStringUTF in a loop. Allocating too much "java" memory, or creating too many locals (512 in dalvik, and something like 16 in java) will be a problem.

This is incorrect, you need to delete any reference you create. Local references are thread-specific so they are automatically destroyed when your thread exits, but if you forget to delete them before that, you'll have the equivalent of a memory leak.

gadget

unread,
Mar 15, 2013, 10:54:32 AM3/15/13
to andro...@googlegroups.com
Then this isn't true?

"A local reference is valid only within the dynamic context of the native method that creates it, and only within that one invocation of the native method. All local references created during the execution of a native method will be freed once the native method returns."

source: http://192.9.162.55/docs/books/jni/html/refs.html#27431

gadget

unread,
Mar 15, 2013, 10:57:32 AM3/15/13
to andro...@googlegroups.com
I think I see what you meant. If this is a true native thread, then since we never return to Java, locals will accumulate. If, however, you're coming from Java to do some native code and then back, then locals will be freed automatically


On Thursday, March 14, 2013 6:18:05 AM UTC-7, Digit wrote:

David Turner

unread,
Mar 15, 2013, 1:19:53 PM3/15/13
to andro...@googlegroups.com
On Fri, Mar 15, 2013 at 3:54 PM, gadget <avraz...@gmail.com> wrote:
Then this isn't true?

"A local reference is valid only within the dynamic context of the native method that creates it, and only within that one invocation of the native method. All local references created during the execution of a native method will be freed once the native method returns."

source: http://192.9.162.55/docs/books/jni/html/refs.html#27431


Sorry my bad, the above text is correct, but it only applies when a native Java method is called from the VM.
Long-lived native threads that occasionally call the VM through JNI (in the opposite direction), should better delete the local references they create.
Reply all
Reply to author
Forward
0 new messages