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

发布于 2024-11-04 08:25:38 字数 1667 浏览 0 评论 0原文

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

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

如果我在垃圾收集器工作时调用垃圾收集器。

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

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

I'm wondering how does the allocation and disposal of memory allocated for bitmaps work in .NET.

When I do a lot of bitmap creations in loops in a function and call it in succession it will work up until at some point the Bitmap wont be able to allocate memory giving the exception "Invalid parameter" for the size specified.

If I call the garbage collector from while to while it works.

With the following code you are able to repoduce the error:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

后来的我们 2024-11-11 08:25:38

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

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

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

The Bitmap class is inevitably the one where you have to stop ignoring that IDisposable exists. It is a small wrapper class around a GDI+ object. GDI+ is unmanaged code. The bitmap occupies unmanaged memory. A lot of it when the bitmap is large.

The .NET garbage collector ensures that unmanaged system resources are released with the finalizer thread. Problem is, it only kicks into action when you create sufficient amounts of managed objects to trigger a garbage collection. That won't work well for the Bitmap class, you can create many thousands of them before generation #0 of the garbage collected heap fills up. You will run out of unmanaged memory before you can get there.

Managing the lifetime of the bitmaps you use is required. Call the Dispose() method when you no longer have a use for it. That's not always the golden solution, you may have to re-think your approach if you simply have too many live bitmaps. A 64-bit operating system is the next solution.

南…巷孤猫 2024-11-11 08:25:38

.NET 位图 类“封装 GDI+ 位图”,这意味着您应该调用 Dispose位图 当你完成后,

“始终在您之前调用 Dispose
发布您对
图像。不然资源就这样了
使用不会被释放,直到
垃圾收集器调用 Image
对象的 Finalize 方法。”

The .NET Bitmap class "encapsulates a GDI+ bitmap", that means you should call Dispose on a Bitmap when you are finished with it,

"Always call Dispose before you
release your last reference to the
Image. Otherwise, the resources it is
using will not be freed until the
garbage collector calls the Image
object's Finalize method."

未央 2024-11-11 08:25:38

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

它只是一个语法快捷方式

try
{
 ...   
}
finally
{
    ...Dispose();
}

Why don't you use using keyword. Just encapsulate your Bitmap object in it and Compiler will ensure that Dispose method is called.

Its simply a syntactic shortcut for

try
{
 ...   
}
finally
{
    ...Dispose();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文