PlaySound API を繰り返し呼び出すと Audiodg.exe のメモリ使用量が増加する
こんにちは、マルチメディアサポートチームです。今回は、PlaySound API を繰り返し呼び出した場合に、Audiodg.exe のメモリ使用量が増加し続ける現象についてご説明します。
なお、本現象につきましては、音声の再生時のパフォーマンスを重視する必要があり、メモリ解放が低優先度となる仕様に基づく動作となります。
事象発生までの流れ
PlaySound API は、Windows にて特定の音データを再生するために利用する代表的なAPI です。
PlaySound function
https://msdn.microsoft.com/en-us/library/windows/desktop/dd743680(v=vs.85).aspx
このAPI は基本的に指定された音データのみを一度 再生します。そのため、継続的に音を再生する場合や複数の音源を再生する場合など、利用目的によっては、PlaySound API を繰り返して呼ぶ利用方法が考えられます。
ただ、繰り返して呼び出す利用方法にて、API の呼び出し間隔が(1 秒未満など) 短い場合は、時間の経過とともにOS 内のモジュールAudiodg.exe のメモリ使用量が徐々に増加する事象が発生します。この事象は、PlaySound が呼び出されている間は継続して発生します。
増加量の度合いは呼び出しの頻度や音データのサイズに影響されますが、目安として、50~100 ミリ秒程度の間隔でPlaySound API を繰り返し呼び出した場合、30~40 時間程度でAudiodg.exe のメモリ使用量が1 GB 単位に至ります。
事象の発生要因について
この事象は、Audiodg.exe が再生側のパフォーマンスを重視した処理を行っている結果として、メモリの解放処理が遅延しているために発生します。音声の再生には、周波数に応じたサンプリングデータ生成が必要です。もし処理が間に合わない場合には、正しい音が再生できないこととなるため、音声再生のパフォーマンスを重視する仕様となっております。
PlaySound API を呼び出した際は、OS 内の処理として、Windows オーディオ サービス (Audiosrv) がAudiodg.exe に対し呼び出し(RPC ※1) をかけます。Audiodg.exe は、その呼び出しに応じて、音の再生など必要な処理を行います。この際に、音データなど処理に必要なデータは(C++) オブジェクトとしてOS よりメモリ内に割り当てられています。
ただ、その再生処理が完了した後でも、Audiodg.exe は、その同じRPC 処理の中で割り当てられたメモリの開放を即座に行いません。これは、「音の再生」という優先度の高い処理を滞りなく実行するための、パフォーマンスの維持を考慮した結果の動作となっています。
その代わりAudiodg.exe は、後にメモリの開放を行うための印として、処理に利用したオブジェクトに対して、「利用済み」であることを表すフラグをセットします。
Audiodg.exe は、実際にメモリの開放を行う処理を、このフラグの有無をベースに、専用のスレッドを通して一定の間隔で行います。ただ、解放処理を実行するには、まずスレッドが開始できる状態である必要があります。
今回の事象が発生するような、短い間隔での音再生が繰り返されるAPI の利用方法では、Audiodg.exe にて専用スレッドの開始を行うためのリソースがない状況が続きます。その結果、解放処理は開始されず、メモリの割り当てのみが繰り返し行われ、メモリ使用量の増加が継続して発生します。
もし解放専用のスレッドが実行できる程度のリソースをAudiodg.exe が確保できる場合は、解放処理が始まり、メモリの開放が行われます。そのため、PlaySound API を実行しているプログラムが終了した場合、メモリ使用量の低下が見込まれます。
なお、この事象はあくまで後負荷の処理に起因した「メモリ使用量の増加」であるため、メモリ リークは発生しておりません。Audiodg.exe にて発生するメモリー リークについては、以下の既知の問題がありますが、この事象との関連性はございません。
Handle leak occurs in the Audiodg.exe process in Windows 7 or in Windows Server 2008 R2
対処法について
上記の詳細の通り、この事象は、メモリの開放を行う動作が実行されることで解消します。そのため、対処法としては、以下の方法が考えられます。
· PlaySound API を繰り返し呼び出す間隔を(数秒程度に) 広げ、解放処理を実行できる程度のリソースをAudiodg.exe で控えられるようにする
· PlaySound API を一定期間呼ばない処理を加える
· 以下のコマンドなどで、Windows オーディオ サービス(Audiosrv) を一度 停止し、強制的に割り当てられたメモリを解放した後、サービスを再開させる
Net stop audiosrv
Net start audiosrv
補足
※ 1: Remote Procedure Call (RPC) の概要については、以下のドキュメントをご参照ください。
Remote Procedure Call https://msdn.microsoft.com/en-us/library/windows/desktop/aa378651(v=vs.85).aspx