- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
快速背景:
app是一个音频播放器,ffmpeg编译为native共享对象用于解码,单独的native library编译为共享对象用于音频处理,AudioTrack用于输出处理后的音频。所有音频功能都封装在一个类中,该类使用静态类变量来确保只有一个实例。在这个类中:一个java线程用于从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/
我是一名优秀的程序员,十分优秀!