当没有剩余内存时,.Net 和 Bitmap 不会被 GC 自动处理
我想知道.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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
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.
.NET
位图
类“封装 GDI+ 位图”,这意味着您应该调用Dispose
在位图 当你完成后,
The .NET
Bitmap
class "encapsulates a GDI+ bitmap", that means you should callDispose
on aBitmap
when you are finished with it,为什么不使用
using
关键字。只需将 Bitmap 对象封装在其中,Compiler 将确保调用 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