簡単な背景: アプリはオーディオ プレーヤーであり、ffmpeg はネイティブ共有オブジェクトとしてコンパイルされ、デコードに使用されます。別のネイティブ ライブラリは共有オブジェクトとしてコンパイルされ、オーディオ処理に使用されます。AudioTrack は処理されたオーディオの出力に使用されます。すべてのオーディオ機能は、静的クラス変数を使用して 1 つのインスタンスのみを保証するクラスにラップされます。このクラス内: Java スレッドを使用して ffmpeg からデータを取得し、ネイティブ処理ライブラリを介してオーディオ処理を完了します。ネイティブ処理呼び出しは、構成に応じて 2 ~ 3.5 ミリ秒かかります。処理されたオーディオは、読み取りおよび書き込みカウント セマフォによって管理される ByteBuffers の配列にあります。別の Java スレッド ByteBuffer.gets は、オーディオのブロックを取得し、sem カウントをデクリメントして、byte[] データを AudioTrack に送信します。AudioTrack は、getMinBufferSize によって返されるサイズの 2 倍のバッファー サイズでストリーミング モードで構成されます。オーディオ データは、チャンネル ブロックごとに 512 サンプル (ステレオの場合は 2048 バイト) でシステムを通過します。
問題: ランダムな時間の間、すべてがうまく機能し、その後すべてが停止し、クラッシュも SIGSEG も発生しません。アプリは単に CPU のほとんどを消費し、何もしません。GUI が応答せず、ADT のデバッガーがアプリへの接続を失います。シェルと 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 で 2 つのインスタンスのみ、1 つは processAudiobuffer で、もう 1 つは tryLock で実行されます。tryLock は stepServer と framesReady から呼び出されます。ハングしたアプリからスタック ダンプを取得できませんでした。kill -3 はサスペンド #1 threadid=2 (pcf=0) でスピンを生成します。アプリは ANR と宣言されていないため、/data/ANR/traces.txt はありません。
私の概要 - GC はその役割を果たし、ネイティブ ヒープを検査しています。ドキュメントによると、GC は JNI 呼び出しの途中で中断されません。ただし、AudioTrack スレッドを一時停止する必要があり、ネイティブ ヒープ インスペクションが AudioTrack の processAudioBuffer の実行と一致すると、デッドロックが発生します。
質問: 1) 開発プラットフォームと JTAG デバッガーを除いて、ネイティブ コンポーネントのスタック トレースは確実に役立ちます。他に試す方法はありますか? 2) GC と AudioTrack がデッドロック ルートをたどる問題を見た人はいますか? 3) この問題を回避するために、GC dlmalloc_inspect_all 呼び出しを抑制または同期できる可能性はありますか? 4) この問題を解決するための提案はありますか?
参考になったらコードを投稿していただければ幸いです