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

Mar*_*mić 11 .net c# memory garbage-collection bitmap

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

当我在一个函数的循环中做很多位图创建并连续调用它时,它会一直工作,直到某个时候Bitmap不能分配内存,给出指定大小的异常"Invalid parameter".

如果我在它工作的同时调用垃圾收集器.

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

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
        }       
     }
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 17

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

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

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


Mit*_*eat 16

.NET Bitmap类"封装了一个GDI +位图",这意味着你应该DisposeBitmap完成它时调用它,

"在释放对Image的最后一个引用之前总是调用Dispose.否则,在垃圾收集器调用Image对象的Finalize方法之前,它将不会释放它所使用的资源."