Help us understand the problem. What is going on with this article?

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

背景

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 では起こりません。

サンプルコードはこちら

satohnorio
備忘録として記事を書いています。 記事の内容は個人の見解であり、所属する企業を代表するものではありません。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした