none
JPEGファイルを読み込むとWindows2000でのみ発生するメモリリーク? RRS feed

  • 質問

  • .NET Framework 2.0でフォルダ(C:\\jpeg3)内のすべての画像ファイルを順に読み込み、

    縮小画像をメモリに保持するプログラムを作成しました。

     

    C:\\jpeg3フォルダは1600x2400ピクセルの真っ白なカラーJPEGファイルが512個入ったフォルダです。

     

    このプログラムをWindows2000、XP、Vistaで実行してみたところ、

    Windows2000でのみ、140~160枚目ぐらいのJPEG画像を読み込んだあたりで

    g.DrawImage()の行で、System.OutOfMemoryExceptionが発生します。

    そこで2台のメモリ搭載量の異なるWindows2000で試しましたが、メモリ搭載容量にかかわりなく

    140~160枚目ぐらいのJPEG画像を読み込んだあたりでSystem.OutofMemoryExceptionが発生します。

     

    問題の発生するプログラム: JpegResize2.cs

    Code Snippet

    namespace JpegResize2
    {
        class Program
        {
            private static System.Drawing.Size newSize = new System.Drawing.Size(160, 240);

            static void Main(string[] args)
            {
                System.IO.DirectoryInfo d = new System.IO.DirectoryInfo("C:\\1\\jpgs3");
                System.IO.FileInfo[] fis = d.GetFiles();
                System.Collections.Generic.List bitmaps = new System.Collections.Generic.List();

                int i = 0;
                foreach (System.IO.FileInfo fi in fis) {
                    System.Console.WriteLine("{0} / {1}", ++i, fis.Length);
                    System.Drawing.Bitmap resampledBitmap;
                    using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(fi.FullName)) {
                        resampledBitmap = new System.Drawing.Bitmap(newSize.Width, newSize.Height);
                        using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(resampledBitmap)) {
                            g.DrawImage(bitmap, 0, 0, newSize.Width, newSize.Height);
                            g.Dispose();
                        }
                        bitmap.Dispose();
                    }
                    bitmaps.Add(resampledBitmap);
                }
            }
        }
    }

     

    Exception発生時のエラーダイアログの内容:

    'System.OutOfMemoryException' のハンドルされていない例外が System.Drawing.dll で発生しました。

    追加情報: メモリが不足しています。

     

    Exception発生時のスタック:

    Code Snippet
      System.Drawing.dll!System.Drawing.Graphics.CheckErrorStatus(int status) + 0x53 バイト 
      System.Drawing.dll!System.Drawing.Graphics.DrawImage(System.Drawing.Image image, int x, int y, int width, int height) + 0x99 バイト 
    > JpegResize2.exe!JpegResize2.Program.Main(string[] args = {次元:[0]}) 行 20 + 0x4a バイト C#
      [ネイティブからマネージの移行] 
      [マネージからネイティブへの移行] 
      mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x32 バイト 
      Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2b バイト 
      mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x3b バイト 
      mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x81 バイト 
      mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x40 バイト 

     

     

    いくつか試行錯誤した結果は以下の通りです。

     

    • Windows2000、XP、Vistaで実行したところ、Windows2000でのみ発生。
    • 1600x2400x24bppのBMPファイルが512枚入ったフォルダを読み込ませると停止せず、1600x2400ピクセルのカラーJPEGファイルが512枚入ったフォルダを読み込ませると150枚前後でOutOfMemoryExceptionが発生。
    • 3200x4800ピクセルのカラーJPEGファイルが512枚入ったフォルダを読み込ませると33~39枚前後でOutOfMemoryExceptionが発生。

    おそらく私のプログラムの初歩的なバグだと思うのですが、数日ああでもないこうでもないと試行錯誤しても

    解決の糸口は見つかりませんでした。どなたか同様の問題を経験した方はいらっしゃいませんか?

    2007年7月18日 13:37

すべての返信

  • 余計なものが入ってる・・・

     

                 using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(fi.FullName)) {
                        resampledBitmap = new System.Drawing.Bitmap(newSize.Width, newSize.Height);
                        using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(resampledBitmap)) {
                            g.DrawImage(bitmap, 0, 0, newSize.Width, newSize.Height);
      //                      g.Dispose();
                        }
     //                   bitmap.Dispose();
                    }
                    bitmaps.Add(resampledBitmap);

     

    この2行余計です。

     

    ただ実際にはメモリサイズじゃなくって、BITMAPハンドルが取得できていないんだと思いますが、どんなもんでしょう?

     

    2007年7月19日 11:07
  • 間違えていたらすみません。

    遠い記憶をたどるとこのパターンって画像ファイルが開きっぱなしになるバグっぽい現象があった気がします。

    画像ファイルを確実にクローズするやり方に変えてみたらどうでしょうか?

     

    FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
       bitmap = new Bitmap( System.Drawing.Image.FromStream(fs) ) ;
       fs.Close();

    2007年7月19日 14:08
  • 返信ありがとうございます。
    ご指摘の2箇所を削除してみましたが直りませんでした。

    >ただ実際にはメモリサイズじゃなくって、BITMAPハンドルが取得できていないんだと思いますが、どんなもんでしょう?

    BMPの読み込みでは問題は起こりません。Windows2000でJPEGの読み込みを行ったときのみOutOfMemoryExceptionが発生します。

    2007年7月19日 14:09
  • 返信ありがとうございます。ファイルの読み込み方法をご指摘の方法に変更したところ、直りました。

    以下に正常に動作するようになったプログラムを貼り付けます。

    ありがとうございました。

     

    (かぎ括弧が消えているかもしれませんがbitmapsはSystem.Drawing.BitmapのListです)

     

    Code Snippet

    namespace JpegResize2
    {
        class Program
        {
            private static System.Drawing.Size newSize = new System.Drawing.Size(160, 240);

            static void Main(string[] args)
            {
                System.IO.DirectoryInfo d = new System.IO.DirectoryInfo("C:\\1\\jpgs3");
                System.IO.FileInfo[] fis = d.GetFiles();
                System.Collections.Generic.List<System.Drawing.Bitmap> bitmaps = new System.Collections.Generic.List<System.Drawing.Bitmap>();

                int i = 0;
                foreach (System.IO.FileInfo fi in fis) {
                    System.Console.WriteLine("{0} / {1}", ++i, fis.Length);
                    System.Drawing.Bitmap resampledBitmap;
                    System.IO.FileStream fs = new System.IO.FileStream(fi.FullName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                    using(System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(System.Drawing.Image.FromStream(fs))) {
                        resampledBitmap = new System.Drawing.Bitmap(newSize.Width, newSize.Height);
                        using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(resampledBitmap)) {
                            g.DrawImage(bitmap, 0, 0, newSize.Width, newSize.Height);
                        }
                    }
                    fs.Close();
                    bitmaps.Add(resampledBitmap);
                }
            }
        }
    }

     

     

    2007年7月19日 14:47
  • 私が試して駄目だったプログラムも何通りか貼り付けておきます。

    何かの参考になるかもしれませんので

     

    OutOfExceptionが発生する駄目なプログラム1:

    Code Snippet

    System.Drawing.Bitmap resampledBitmap;
     System.IO.FileStream fs = new System.IO.FileStream(fi.FullName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
     using(System.Drawing.Image image = System.Drawing.Image.FromStream(fs)) {
         resampledBitmap = new System.Drawing.Bitmap(newSize.Width, newSize.Height);
         using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(resampledBitmap)) {
             g.DrawImage(image, 0, 0, newSize.Width, newSize.Height);
         }
     }
     fs.Close(); 
     bitmaps.Add(resampledBitmap);

     

    OutOfExceptionが発生する駄目なプログラム2: 

    Code Snippet
     System.Drawing.Bitmap resampledBitmap;
     System.IO.FileStream fs = new System.IO.FileStream(fi.FullName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
     using(System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(fs)) {
         resampledBitmap = new System.Drawing.Bitmap(newSize.Width, newSize.Height);
         using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(resampledBitmap)) {
             g.DrawImage(bitmap, 0, 0, newSize.Width, newSize.Height);
         }
     }
     fs.Close(); 
     bitmaps.Add(resampledBitmap);

     

    OutOfExceptionが発生しないプログラム:

    Code Snippet

    System.Drawing.Bitmap resampledBitmap;
     System.IO.FileStream fs = new System.IO.FileStream(fi.FullName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
     using(System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(new System.Drawing.Bitmap(fs))) {
         resampledBitmap = new System.Drawing.Bitmap(newSize.Width, newSize.Height);
         using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(resampledBitmap)) {
             g.DrawImage(bitmap, 0, 0, newSize.Width, newSize.Height);
         }
     }
     fs.Close();
     bitmaps.Add(resampledBitmap);

     

     

     

     

     

     

     

    2007年7月19日 15:32