没有内存时,GC不会自动处理.Net和Bitmap

时间:2011-04-30 00:23:42

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

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

当我在一个函数的循环中做很多位图创建并连续调用它时,它会工作到某个时刻,Bitmap将无法分配内存,从而为指定的大小提供异常“Invalid parameter”。 / p>

如果我在运行时调用垃圾收集器。

使用以下代码,您可以重新生成错误:

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
        }       
     }
}

3 个答案:

答案 0 :(得分:17)

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

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

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

答案 1 :(得分:14)

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

  

“总是在你面前调用Dispose   发布你的最后一个引用   图片。否则,它是资源   使用将不会被释放,直到   垃圾收集器调用Image   对象的Finalize方法。“

答案 2 :(得分:1)

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

它只是

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