【问题标题】:.Net and Bitmap not automatically disposed by GC when there is no memory left当没有剩余内存时,.Net 和 Bitmap 不会被 GC 自动处理
【发布时间】:2011-08-15 20:48:29
【问题描述】:

我想知道为位图分配的内存的分配和处置如何在 .NET 中工作。

当我在一个函数的循环中创建大量位图并连续调用它时,它将一直工作到某个时候位图将无法分配内存,给出指定大小的“无效参数”异常。

如果我从 while 到 while 调用垃圾收集器。

使用以下代码,您可以重现错误:

class BitmapObject {
    public bool Visible {
        get { return enb; }
        set { enb = value; }
    }
    private bool enb;
    private Bitmap bmp;
public BitmapObject(int i, bool en)
{
    enb = en;
    bmp = new Bitmap(i, i);


   }
}

class Pool<T> where T : BitmapObject
{
    List<T> preallocatedBitmaps = new List<T>();
public void Fill() {
    Random r = new Random();
    for (int i = 0; i < 500; i++) {
        BitmapObject item = new BitmapObject(500, r.NextDouble() > 0.5);
        preallocatedBitmaps.Add(item as T);
    }
}

public IEnumerable<T> Objects
{
    get
    {
        foreach (T component in this.preallocatedBitmaps)
        {
            if (component.Visible)
            {
                yield return (T)component;
            }
        }


     }
    }
}

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
{
    for (int i = 0; i < 10; i++ )
    {
        Test();

            // without this it breaks
            //GC.Collect();
            //GC.WaitForPendingFinalizers();
        }

        Console.ReadKey();
    }

    private static void Test() {
        Pool<BitmapObject> pool = new Pool<BitmapObject>();
        pool.Fill();

        for (int i = 0; i < 100; i++)
        {
            var visBitmaps = pool.Objects;
            // do something
        }       
     }
}

【问题讨论】:

  • GC 从不 清理本地资源,只清理 Bitmap 对象本身。您有责任致电Dispose()
  • @Ed,虽然在技术上是正确的,但当 GC 清理 Bitmap 时,Bitmap 的终结器将处理资源。但你是对的,你不应该依赖它。
  • @Talljoe:是的,你是对的,它会的。

标签: c# .net memory garbage-collection bitmap


【解决方案1】:

.NET Bitmap 类“封装了一个 GDI+ 位图”,这意味着您应该在完成后在 Bitmap 上调用 Dispose

“总是先调用 Dispose 发布您对 图片。否则,它的资源 using 将不会被释放,直到 垃圾收集器调用图像 对象的 Finalize 方法。”

【讨论】:

  • 这意味着如果泛型类中使用了一些位图,那么泛型类应该实现 IDIsposable 并且 T 必须是一次性的才能被该类调用?
【解决方案2】:

为什么不使用using 关键字。只需将您的 Bitmap 对象封装在其中,Compiler 将确保调用 Dispose 方法。

它只是

的语法快捷方式
try
{
 ...   
}
finally
{
    ...Dispose();
}

【讨论】:

  • 因为位图可以是在通用外部列表中使用的类的私有字段......但我认为 IDisposable 是去这里的方式......
【解决方案3】:

Bitmap 类不可避免地是您必须停止忽略 IDisposable 存在的类。它是一个围绕 GDI+ 对象的小型包装类。 GDI+ 是非托管代码。位图占用非托管内存。当位图很大时,很多。

.NET 垃圾收集器确保使用终结器线程释放非托管系统资源。问题是,只有当您创建足够数量的 托管 对象来触发垃圾回收时,它才会生效。这不适用于 Bitmap 类,您可以在垃圾收集堆的第 0 代填满之前创建数千个。在到达那里之前,您将用完非托管内存。

需要管理您使用的位图的生命周期。当您不再使用 Dispose() 方法时,请调用它。这并不总是黄金解决方案,如果您只是有太多实时位图,您可能需要重新考虑您的方法。下一个解决方案是 64 位操作系统。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-26
    • 2014-12-12
    • 1970-01-01
    • 2014-10-04
    • 1970-01-01
    • 2020-07-24
    相关资源
    最近更新 更多