【问题标题】:Unusual Physical memory usage when huge number of bitmap images are created and saved as one bit per pixel image当创建大量位图图像并将其保存为每像素图像一位时,物理内存使用异常
【发布时间】:2015-01-14 11:26:36
【问题描述】:

我正在尝试从 base 64 字符串创建大量每像素 1 位的 bmp 图像并保存。根据要求,在短时间内创建大量图像(平均在短时间内创建 50,000 到 1,00,000 个)。我正在使用下面的代码。

  public void CreateoneBppImageAndSave(String base64ImageString,String ImagePathToSave)
    {
        byte[] byteArray = Convert.FromBase64String(base64ImageString);

        System.Drawing.Image img = byteArrayToImage(byteArray);
        Bitmap objBitmap = new Bitmap(img);

        BitmapData bmpData = objBitmap.LockBits(new Rectangle(0, 0, objBitmap.Width, objBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
        Bitmap oneBppBitmap = new Bitmap(objBitmap.Width, objBitmap.Height, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0);

        oneBppBitmap.Save(ImagePathToSave, ImageFormat.Bmp);
        img.Dispose();
        objBitmap.Dispose();
        objBitmap.UnlockBits(bmpData);
        oneBppBitmap.Dispose();
    }

    private Image byteArrayToImage(byte[] byteArrayIn)
    {
        using (MemoryStream ms = new MemoryStream(byteArrayIn))
        {
            return Image.FromStream(ms);
        }
    }

这里的物理内存使用率非常高。通常生成的图像大小为 200x200 到 754x1024 。一段时间后,物理内存使用量达到极限并抛出内存不足异常。物理内存每 5-10 秒增加 0.01 GB。请帮助我在内存使用方面优化代码

【问题讨论】:

  • 你为什么手动调用Dispose()而不使用using语句?
  • 我已经通过显式调用 dispose 来处理任何可以处理的对象。
  • 在 object.dispose() 上使用一次性“使用”有什么好处
  • 你不应该打电话给UnlockBitsobjBitmap吗?
  • 根据您的更正,您在处理后致电UnlockBits,这是另一个错字还是您真正在做什么?

标签: c# memory-management bitmap out-of-memory


【解决方案1】:

您在objBitmap 上致电LockBits,但是您在oneBppBitmap 上致电UnlockBits。您应该在调用 lock 的同一对象上调用 unlock。

至于我在 cmets 中提到的 using 语句,一个 using 语句变成了这个

using(SomeType obj = new SomeType())
{
   // Some code
}

相当于这个

SomeType obj = new SomeType())
try
{
    // Some code
}
finally
{
    obj.Dispose();
}

这保证即使在// Some Code 中抛出异常,dispose 操作仍然会发生。如果您在创建和处置之间的任何函数引发异常,那么您的代码将不会处置其任何对象。

这是一个重新编写的版本,其中包含我提到的所有更正以及其他一些更正......

public void CreateoneBppImageAndSave(String base64ImageString,String ImagePathToSave)
{
    byte[] byteArray = Convert.FromBase64String(base64ImageString);

    using(Image img = byteArrayToImage(byteArray))
    using(Bitmap objBitmap = new Bitmap(img))
    {    
        BitmapData bmpData = objBitmap.LockBits(new Rectangle(0, 0, objBitmap.Width, objBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
        try
        {
            using(Bitmap oneBppBitmap = new Bitmap(objBitmap.Width, objBitmap.Height, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0))
            {        
                oneBppBitmap.Save(ImagePathToSave, ImageFormat.Bmp);
            }
        }
        finally
        {
            //put the unlock in a finally to make sure it happens.
            objBitmap.UnlockBits(bmpData);
        }
    }
}

编辑:如果这真的在你的代码中

objBitmap.Dispose();
objBitmap.UnlockBits(bmpData);

这是您问题的根源,您不应在处置后调用类的任何方法。这是using 的另一个好处,您不能延迟调用方法,因为离开using 块时变量会超出范围。

【讨论】:

  • 哎呀。我提到的代码是错误的。真正的代码是 objBitmap.UnlockBits(bmpData);。我正在编辑问题。请原谅我。
  • +1 为您的建议。但在实际代码中,我正在解锁我已锁定位的对象上的位。是否有任何其他建议可以解决此问题?
  • @amesh 看到我的更新版本,如果你像我一样重写它,你还会遇到问题吗?你可能会遇到一个异常,你正在默默地吞下调用堆栈和Dispose 和@ 987654334@ 可能永远不会被调用。
  • 谢谢斯科特。我会试试这个并恢复。
  • @amesh 这些内存号,您在连接调试器的情况下运行时得到它们吗?调试器极大地影响了对象从内存中删除的方式,您是否遇到 OutOfMemory 异常,或者只是您认为它“使用大量内存”并想减少它?
猜你喜欢
  • 2019-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-13
  • 2015-11-03
  • 1970-01-01
相关资源
最近更新 更多