GdiplusStartup と GdiplusShutdown を繰り返すとメモリ リークする

こんにちは、Platform SDK (Windows SDK) サポートチームです。
アプリケーションからの GDI+ 利用方法によってメモリ リークする現象についてご案内します。

 

現象

アプリケーションから GDI+ を利用する前に GdiplusStartup 関数を、利用したあとに GdiplusShutdown 関数を実行しますが、この対をアプリケーション内で何度も実行すると少しづつメモリが解放されない状態で残ります。このメモリは、アプリケーション プロセスが終了するまで解放されません。

アプリケーションで画像を処理するときにのみ GDI+ を利用しているなど、常時使わずに一時的に利用する場合にこのような実装になることがあります。

実装例:
void OnProcessing()
{

Gdiplus::GdiplusStartupInput gdiplusStartupInput = { 1, NULL, FALSE, FALSE };
ULONG_PTR gdiplusToken = NULL;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

// GDI+ を利用したイメージ処理など
// ...

Gdiplus::GdiplusShutdown(gdiplusToken);

}

メニュー操作などからこの関数を何度も実行していると、解放されないメモリが蓄積していきます。

 

原因

この現象は、GDI+ 内から間接的に利用している Text Services Framework (TSF) の不具合によって発生します。

GDI+ の中では、GdiplusStartup 関数実行時に作業用のスレッドおよびウィンドウを作成し、GdiplusShutdown 関数実行時にこれらを破棄します。ここで作成されるウィンドウは、処理の中で一度も表示されず、ユーザーの入力フォーカスを得ることもありません。

TSF では、スレッドで最初にウィンドウが作成されるときにユーザー入力を管理するメモリを確保し、ウィンドウがすべてクローズされたあと、最後にスレッドが終了するところでそのメモリを解放します。しかしながら、ウィンドウが入力フォーカスを得ることがないなど、メモリを解放しないことがあります。

GDI+ からのスレッド及びウィンドウ利用では、この解放されない条件に合ってしまい、初期化と終了を繰り返すことで解放されないメモリが蓄積することになります。

なお、通常のユーザー操作を伴う利用ではこの条件に合わないため、現象が発生することはありません。

 

回避方法

現在、この問題を修正する予定がありません。

アプリケーション側で GDI+ の初期化と終了の処理を複数回実行しない実装にすることを検討していただけますようお願いします。

 

関連情報

GdiplusStartup function

https://msdn.microsoft.com/en-us/library/windows/desktop/ms534077.aspx

GdiplusShutdown function

https://msdn.microsoft.com/en-us/library/windows/desktop/ms534076.aspx