4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Windows 10 & .NET Framework の環境で印刷するとメモリリークする

Posted at

背景

Windows 7 の頃には問題なかった処理が Windows 10 に変更するとメモリリークするようになったので調べてみた。

再現コード

var server = new LocalPrintServer();
var queue = server.GetPrintQueue(this.SelectedPrinter.Value);
var writer = PrintQueue.CreateXpsDocumentWriter(queue);
if (!String.IsNullOrWhiteSpace(this.SelectedFilePath.Value))
{
    writer.Write(this.SelectedFilePath.Value);
}

解説

Windows 7 の頃はこれで問題なかったのだが、 Windows 10 では GetPrintQueue() で取得した PrintQueue がメモリリークすることがある。

具体的には、 XpsDocumentWriter.Write() を実行すると、 Windows 10 では COM Surrogate (dllhost.exe) に処理を委譲するようになっており、印刷が終わっても PrintQueue が破棄されるまでメモリが解放されないようだ。

プリンタドライバを古いものに替えると起きなくなったので、ドライバの不具合を疑いメーカーに問い合わせした所、 PrintTicket に対応したドライバを使用すると起きるらしい。
dllhost.exe は OS のモジュールなのでメーカー側ではどうしようもできないようだ。

解決方法

印刷が終わったら PrintQueue を Dispose すればメモリが解放される。

var server = new LocalPrintServer();
using(var queue = server.GetPrintQueue(this.SelectedPrinter.Value))
{
    var writer = PrintQueue.CreateXpsDocumentWriter(queue);
    if (!String.IsNullOrWhiteSpace(this.SelectedFilePath.Value))
    {
        writer.Write(this.SelectedFilePath.Value);
    }
}

感想

本来、これが行儀のいい書き方なので、困っている人はあまりいないかもしれないが、 Visual Studio で印刷すると同様のリークが起きたりするので、 Microsoft 内でも想定外なバグなのかもしれない。
サンプルのコードなんかを単純にコピペしてる人は困っているかもしれない。

しかし、自分で new したものを Dispose するのは忘れないが、 GetPrintQueue() 内で新規にインスタンスが作成されていると思わないし、フレームワークが返したオブジェクトを勝手に Dispose してもいいのかとか色々考えてしまうので、あまり良い実装でないように思う。

因みにこのリークは .Net Core では起こりません。

サンプルコードはこちら

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?