Is native code interrupted by GC?

1,526 views
Skip to first unread message

ls02

unread,
May 28, 2010, 8:54:51 AM5/28/10
to android-ndk
I assume that native code called from Java layer runs in Java thread
and is interrupted by GC. What happens if I spawn a native thread in
JNI code and call Java objects method from that native JNI code
running in that thread? Does the native thread in this case get
attached to Java and GC will suspend it to run GC on it?

I am looking for a way to have code run without GC interruption. We
have audio processing code that involves custom audio decoding.
Decoding is done in native code and playback done via AudioTrack Java
class. Native thread with decoding gets GC'ed that leads to audio
being choppy. We need either to prevent the decoding and playback
thread from being suspended by GC or figure out how to play decoded
audio directly using native code bypassing Java layer.

appforce.org

unread,
May 28, 2010, 4:03:39 PM5/28/10
to android-ndk
Correct me if I'm wrong, but Dalvik is not aware of non-VM threads and
therefore doesn't suspend them on GC pass.

Olivier Guilyardi

unread,
May 28, 2010, 4:20:10 PM5/28/10
to andro...@googlegroups.com
I did see audio dropouts occuring at the same time as GC when recording using
AudioRecord. It looked like GC caused a big lock of some kind. I'm not saying
that it was interrupting my native threads, because I rely on AudioRecord and
therefore Java to read from the audio hardware. I think this also affected
playback with AudioTrack.

At the time I worked hard to minimize all allocations during recording, and that
quite fixed the problem. But now that I moved the audio engine into a background
service, GC seems not to have such effect anymore... It does occur from time to
time, but dropouts are gone.

Olivier

fadden

unread,
May 28, 2010, 5:52:39 PM5/28/10
to android-ndk
On May 28, 5:54 am, ls02 <agal...@audible.com> wrote:
> I assume that native code called from Java layer runs in Java thread
> and is interrupted by GC. What happens if I spawn a native thread in
> JNI code and call Java objects method from that native JNI code
> running in that thread? Does the native thread in this case get
> attached to Java and GC will suspend it to run GC on it?

Your initial assumption is incorrect.

All threads are Linux pthreads. There is no such thing as a "Java
thread". Some threads are visible to the VM, either because the VM
created them or they were attached with the AttachCurrentThread JNI
call.

The stop-the-world GC mechanism uses safe pointing (i.e. each thread
periodically checks to see if it needs to suspend). Native code is
considered "safe", in that it has no way of doing anything that can
confuse the GC without making a JNI call. The entry point of all JNI
calls has an explicit check for thread suspension.

So, if you have a thread that is either not known to the VM, or is
known but is quietly executing without making any JNI calls, it will
continue to run while the GC does its thing.

ls02

unread,
May 28, 2010, 6:45:21 PM5/28/10
to android-ndk
So what happens if I create new pthread in native code. I can run
audio decoding in it but to play decoded PCM samples I still need to
make call into Java layer to use AudioTrack class since Android does
not provide native access to do this. What happens to this native
thread that calls into Java? Will it be GC'ed?

David Turner

unread,
May 28, 2010, 9:17:30 PM5/28/10
to andro...@googlegroups.com
On Fri, May 28, 2010 at 3:45 PM, ls02 <aga...@audible.com> wrote:
So what happens if I create new pthread in native code. I can run
audio decoding in it but to play decoded PCM samples I still need to
make call into Java layer to use AudioTrack class since Android does
not provide native access to do this. What happens to this native
thread that calls into Java? Will it be GC'ed?

to be able to call Java from your thread, you will need to make it known to the VM first. I don't recall the details though, fadden might be able to tell you.
 
On May 28, 5:52 pm, fadden <fad...@android.com> wrote:
> On May 28, 5:54 am, ls02 <agal...@audible.com> wrote:
>
> > I assume that native code called from Java layer runs in Java thread
> > and is interrupted by GC. What happens if I spawn a native thread in
> > JNI code and call Java objects method from that native JNI code
> > running in that thread? Does the native thread in this case get
> > attached to Java and GC will suspend it to run GC on it?
>
> Your initial assumption is incorrect.
>
> All threads are Linux pthreads.  There is no such thing as a "Java
> thread".  Some threads are visible to the VM, either because the VM
> created them or they were attached with the AttachCurrentThread JNI
> call.
>
> The stop-the-world GC mechanism uses safe pointing (i.e. each thread
> periodically checks to see if it needs to suspend).  Native code is
> considered "safe", in that it has no way of doing anything that can
> confuse the GC without making a JNI call.  The entry point of all JNI
> calls has an explicit check for thread suspension.
>
> So, if you have a thread that is either not known to the VM, or is
> known but is quietly executing without making any JNI calls, it will
> continue to run while the GC does its thing.

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


Ted Neward

unread,
May 28, 2010, 9:34:17 PM5/28/10
to andro...@googlegroups.com
In classic JNI (which I assume is the case for Android as well), the native
thread has to "attach" itself to the JVM in order to safely call back in to
the JVM. So if your native thread calls back into the JVM, during that call
you're now putting yourself at risk for the collector to pause you while it
collects.

What might be better would be to have your native thread drop messages in a
native data structure that can be picked up by a JNI thread and posted back
to the JVM code. That way the native thread remains entirely in native code,
but the communication back to the JVM still happens (albeit in a more
convoluted fashion).

Ted Neward
Java, .NET, XML Services
Consulting, Teaching, Speaking, Writing
http://www.tedneward.com
 

> --
> You received this message because you are subscribed to the Google
> Groups "android-ndk" group.
> To post to this group, send email to andro...@googlegroups.com.
> To unsubscribe from this group, send email to android-

> ndk+uns...@googlegroups.com.

Angus Lees

unread,
May 28, 2010, 9:37:11 PM5/28/10
to andro...@googlegroups.com
Regardless of which thread does what, you only have one processor. If
that processor is busy doing garbage collection for any of your
threads, then it can't be doing your audio work at the same time.

So I'd suggest avoid creating/destroying objects unnecessarily, and
perhaps crank up your audio buffer size to avoid underruns while the
cpu is distracted.

 - Gus

> --
> You received this message because you are subscribed to the Google Groups "android-ndk" group.
> To post to this group, send email to andro...@googlegroups.com.

> To unsubscribe from this group, send email to android-ndk...@googlegroups.com.

ls02

unread,
May 29, 2010, 4:51:49 AM5/29/10
to android-ndk
We have just two threads, one UI thread and another decoding thread
with higher priority. So if we can take decoding thread out of GC
world it would be one less thread to suspend and run GC on. I also
wonder if GC itself runs in a separate thread and with what priority.
If we could set our native decoding thread priority to higher priority
than GC thread priority in theory this thread would not be preempted
by the GC thread until the native decoding thread enters idle state.
> > For more options, visit this group athttp://groups.google.com/group/android-ndk?hl=en.- Hide quoted text -
>
> - Show quoted text -

appforce.org

unread,
May 29, 2010, 5:37:36 AM5/29/10
to android-ndk
GC is performed in dedicated thread, and I believe it runs with
default priority. I think what Angus Lees said about not creating/
destroying object is the best you can do. GC is going to happen no
matter how you setup threads and priorities, and if there isn't
available idle CPU to perform it, you'll notice hiccups. Try to find
the source of excessive GC-ing and relief it.
> > > For more options, visit this group athttp://groups.google.com/group/android-ndk?hl=en.-Hide quoted text -

fadden

unread,
Jun 1, 2010, 6:12:09 PM6/1/10
to android-ndk
On May 29, 2:37 am, "appforce.org" <ogi.andr...@gmail.com> wrote:
> GC is performed in dedicated thread, and I believe it runs with
> default priority.

The GC executes in the thread that caused it. You can cause a GC by
attempting to allocate an object for which there is not currently
enough memory, or explicitly with a call to System.gc(). You may be
thinking of the HeapWorker thread, which executes finalizers and
periodically returns empty pages to the system.

To avoid priority inversion issues, the thread performing the GC will
raise itself to "normal" priority for the duration of the collection,
and lower itself afterward.

ls02

unread,
Jun 1, 2010, 8:46:21 PM6/1/10
to android-ndk
So what priority does this HeapWorker thread have? My primary concern
is not memory management but suspension of audio decoding thread. If I
had all native C/C++ code I could easily create a system where this
thread would have highest priority and would never be suspended until
it enters idle state. I need to achieve the same on Android.
Unfortunately, Android does not provide access to sound card API to
write decoded PCM samples. The only way to do this as far as I know is
to use AudioTrack class that requires callback into Java layer. Right
now I have problems especially on lower power devices when audio
thread is suspended by GC execution which results on choppy playback.

fadden

unread,
Jun 2, 2010, 7:26:02 PM6/2/10
to android-ndk
On Jun 1, 5:46 pm, ls02 <agal...@audible.com> wrote:
> Unfortunately, Android does not provide access to sound card API to
> write decoded PCM samples. The only way to do this as far as I know is
> to use AudioTrack class that requires callback into Java layer. Right
> now I have problems especially on lower power devices when audio
> thread is suspended by GC execution which results on choppy playback.

Clearly there's *some* way to do this, or the music player would have
the same problem. I don't know anything about what media APIs are
public, though, so I don't have an answer for you here.

Doesn't seem like thread priorities are at all relevant here. The
real issue is that you need to keep the sound device fed, and if you
can't give it enough data to span a GC pause you're going to have a
hiccup. How much allocating does the Java code do as part of writing
your data to the device? The less that gets allocated, the longer you
can go without a GC.

Can you feed stuff to android.media.MediaPlayer? (Again, I possess
near-total ignorance of media stuff on the device.)

Olivier Guilyardi

unread,
Jun 2, 2010, 7:36:36 PM6/2/10
to andro...@googlegroups.com
On 06/03/2010 01:26 AM, fadden wrote:
> On Jun 1, 5:46 pm, ls02 <agal...@audible.com> wrote:
>> Unfortunately, Android does not provide access to sound card API to
>> write decoded PCM samples. The only way to do this as far as I know is
>> to use AudioTrack class that requires callback into Java layer. Right
>> now I have problems especially on lower power devices when audio
>> thread is suspended by GC execution which results on choppy playback.

I'm getting near zero dropouts here, it works quite fine. I access the
AudioTrack in a dedicated thread, and I've squashed all allocations on sight.

> Clearly there's *some* way to do this, or the music player would have
> the same problem. I don't know anything about what media APIs are
> public, though, so I don't have an answer for you here.

I think that MediaPlayer bypasses the Java calls which are involved when using
AudioTrack.

> Doesn't seem like thread priorities are at all relevant here. The
> real issue is that you need to keep the sound device fed, and if you
> can't give it enough data to span a GC pause you're going to have a
> hiccup. How much allocating does the Java code do as part of writing
> your data to the device? The less that gets allocated, the longer you
> can go without a GC.

Yeah, don't allocate anything if you can. Also, my engine is now in a background
Service running in a separate process, and it seems like it has helped solving
dropouts when recording with AudioRecord.

> Can you feed stuff to android.media.MediaPlayer? (Again, I possess
> near-total ignorance of media stuff on the device.)

No you can't. Currently, the media C++ API is 100% private.

--
Olivier

Olivier Guilyardi

unread,
Jun 2, 2010, 7:39:48 PM6/2/10
to andro...@googlegroups.com

Sorry, forget this last sentence, I misread what you said. And AFAIK, no the
only way to play live raw audio data is AudioTrack.

--
Olivier

coder zh

unread,
Aug 24, 2016, 6:07:11 PM8/24/16
to android-ndk
Hi, I met the same problem. Could you tell me how did you solve this problem in the end?
Reply all
Reply to author
Forward
0 new messages