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

标签 android garbage-collection audiotrack

快速背景:
app是一个音频播放器,ffmpeg编译为native共享对象用于解码,单独的native library编译为共享对象用于音频处理,AudioTrack用于输出处理后的音频。所有音频功能都封装在一个类中,该类使用静态类变量来确保只有一个实例。在这个类中:一个ja​​va线程用于从ffmpeg获取数据,通过原生处理库完成音频处理。 native 处理调用需要 2 到 3.5 毫秒,具体取决于配置。处理后的音频位于由读取和写入计数信号量管理的 ByteBuffer 数组中。一个单独的 java 线程 ByteBuffer.get 一个音频 block ,减少 sem 计数并将 byte[] 数据发送到 AudioTrack。 AudioTrack 配置为流模式,缓冲区大小为 getMinBufferSize 返回的大小的 2 倍。音频数据以每 channel 512 个样本 block 的形式通过系统,对于立体声,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 来验证 native 内存使用情况。发现并修复了一些泄漏,但根据 libc,没有任何内容超出缓冲区的末端。安装 ByteBuffers 作为解决方法的尝试,之前使用了 byte[] 并表现出相同的问题。我删除了 AudioTrack 并替换为基于 OpenSL ES 的 native 代码,结果相同。毫不奇怪,因为 OpenSL ES 使用了 AudioTrack。 Log.i 样式的调试消息显示写入 AudioTrack 线程停止消耗数据,ffmpeg 读取和处理线程继续,直到 ByteBuffer 数组填满。我已将 System.gc() 调用放在战略位置,有时需要更长时间,但仍会出现挂起。我在 THREAD_PRIORITY_URGENT_AUDIO 设置了“已处理的音频数据到 AudioTrack”线程的优先级,没有观察到任何变化。

我已经广泛搜索了类似问题的实例,但发现的信息很少。我为 Eclipse/ADT 安装了 ARM 的 DS-5 调试功能。该工具能够保持与旋转应用程序的连接。暂停表明 GC 线程处于 dlmalloc_inspect_all 内部的无限循环中,可能试图回收或合并 native 堆。 AudioTrack 线程在暂停时处于 nanosleep,从 usleep 调用,AudioTrack.cpp 中只有两个 this 实例,一个在 processAudiobuffer 中,另一个在 tryLock 中。 tryLock 从 stepServer 和 framesReady 调用。我无法从挂起的应用程序中获取堆栈转储,kill -3 在挂起 #1 threadid=2 (pcf=0) 时产生自旋,该应用程序从未被声明为 ANR,因此没有/data/ANR/traces.txt。

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

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

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

最佳答案

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

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

For more info try

And an excellent article by Dianne Hackborn

关于Android GC和AudioTrack,GC线程卡在dlmalloc_inspect_all和AudioTrack卡住..tryLock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16066414/

相关文章:

java - 如何为 ListView 中的每个项目设置更新和删除按钮

android - 安装插件后无法构建 Cordova 项目

java - 如何在UBUNTU中安装完整的android环境?

java - 如何为Java的GC日志指定时区?

java - 为什么非静态字段不能充当GC根?

java - java中标记为垃圾收集与符合垃圾收集资格

android - 如何使用新的 MediaCodec getInputBuffer(int index)

java - Android:AudioTrack 无法正常工作

android - Google Smart Lock 对话框未出现在 Android O 设备中

android - 如何在Android上使用AudioTrack.getTimestamp()计算延迟?