Android GC和AudioTrack,GC线程卡在dlmalloc_inspect_all和AudioTrack卡住了.. tryLock

时间:2013-04-17 17:30:30

标签: android garbage-collection audiotrack

快速背景: 该应用程序是一个音频播放器,ffmpeg被编译为本机共享对象并用于解码,一个单独的本机库被编译为共享对象并用于音频处理,而AudioTrack用于输出处理过的音频。所有音频功能都包含在一个使用静态类变量的类中,以确保只有一个实例。在这个类中:java线程用于从ffmpeg获取数据并通过本机处理库完成音频处理。本机处理调用需要2到3.5毫秒,具体取决于配置。处理后的音频位于由读写计数信号量管理的ByteBuffers数组中。一个单独的java线程ByteBuffer.gets一个音频块,递减sem计数并将byte []数据发送到AudioTrack。 AudioTrack配置为流模式,缓冲区大小为getMinBufferSize返回的大小的2倍。音频数据通过系统以每通道512个样本块为单位,对于立体声,2048字节。

问题: 一切都很好,随机的时间,然后一切都停止,没有崩溃,没有SIGSEG,应用程序只消耗大部分CPU,什么都不做。 GUI没有响应,ADT中的调试器失去了与应用程序的连接。使用shell和top -m 10 -t,我可以看到应用程序GC线程消耗49%,我假设一个核心。偶尔,AudioTrack弹出的利用率很低。与应用程序关联的其他线程永远不会出现在前10位。这种情况在4.2.2上很快发生,在4.0.1和4.1.1上的确定性较低。

努力解决: 我使用libc.debug.malloc 10来验证本机内存使用情况。找到并修复了几个泄漏,但是根据libc,没有任何泄漏从缓冲区的末端走出来。安装了ByteBuffers作为尝试解决方法,事先使用了byte []并展示了相同的问题。我删除了AudioTrack并替换为基于OpenSL ES的本机代码,结果相同。 OpenSL ES使用AudioTrack并不奇怪。 Log.i样式调试消息显示写入AudioTrack线程停止消耗数据,ffmpeg读取和处理线程继续,直到ByteBuffer数组填充。我已将System.gc()调用放在战略位置,有时需要更长时间,但仍然会发生挂起。我在THREAD_PRIORITY_URGENT_AUDIO设置了'处理过的音频数据到AudioTrack'线程的优先级,没有观察到任何变化。

我已经搜索过类似问题的实例,并且发现的信息非常少。我为Eclipse / ADT安装了ARM的DS-5调试功能。该工具能够保持与旋转应用程序的连接。暂停显示GC线程在dlmalloc_inspect_all内部处于无限循环中,可能尝试回收或合并本机堆。暂停时,AudioTrack线程处于nanosleep状态,从usleep调用,在AudioTrack.cpp中只有两个实例,一个在processAudiobuffer中,另一个在tryLock中。从stepServer和framesReady调用tryLock。我无法从挂起的应用程序获得堆栈转储,在挂起#1 threadid = 2(pcf = 0)时杀死-3产生旋转,应用程序永远不会被声明为ANR,因此没有/data/ANR/traces.txt。

我的概要 - GC正在做它的事情,并检查本机堆。根据文档,GC不会在JNI调用中暂停。它必须暂停AudioTrack线程,当本机堆检查与AudioTrack的processAudioBuffer的执行一致时,会发生死锁。

问题: 1)我肯定会受益于本机组件的堆栈跟踪,缺少开发平台和JTAG调试器,还有其他方法可以尝试吗? 2)有没有人看到GC和AudioTrack出现死锁路线的任何问题? 3)是否有可能抑制或以其他方式同步GC dlmalloc_inspect_all调用以避免此问题? 4)有任何解决这个问题的建议吗?

如果有帮助,我会很乐意发布一些代码

1 个答案:

答案 0 :(得分:0)

面临同样的问题(随机挂起 - 所有停止,没有崩溃,没有SIG,消耗大部分CPU并且什么都不做)。问题出在JNI代码中的内存损坏(如缓冲区溢出)。

此问题似乎也非常依赖设备(我的2台设备100%重复,其他3台没有问题)其他平台(win32,iOS)也没有发现损坏的内存(我正在进行跨平台游戏因此,android的dalvik内存管理器是检测内存错误的好工具,现在我们测试每天构建“内存损坏敏感”设备。有助于确保新的代码稳定性

For more info try

And an excellent article by Dianne Hackborn