如何使用IDisposable接口销毁未托管的对象



我知道如何在类中使用IDisposable接口。但是,我不知道如何释放由类变量分配的内存?例如,在我的类中,我创建了一个列表中有500个位图图像的List<Bitmap>,并在dispose方法中清除该列表。但是,当我使用GC.GetTotalMemory()获取总内存时,它显示出相同的结果。

在这里,我创建了一个由IDisposable接口实现的示例类。

public class disposable : IDisposable
{
List<Bitmap> list = new List<Bitmap>();
public disposable()
{
for (int i=0; i< 500; i++)
{
Bitmap bmp = new Bitmap(1024,768);                    
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(Brushes.Red, new Rectangle(0,0,1024,768));
}
list.Add(bmp);                    
}
}

public void Dispose()
{
list.Clear();
list = null;
}
}

然后我执行了以下代码

static void Main(string[] args)
{
long l1 = GC.GetTotalMemory(true);
using (disposable d = new disposable())
{
//nothing to do
}
long l2 = GC.GetTotalMemory(false);
Console.WriteLine(l1.ToString());
Console.WriteLine(l2.ToString());
Console.ReadKey();
}

输出显示。

181764 //bytes before creating object of disposable class
222724 //bytes after creating object of disposable class

然后我尝试了不使用using关键字和简单声明。

Dim d As New disposable();

但是,它给了我同样的结果。

所以,我的问题是,为什么即使我处理了对象,那些位图图像也分配不出内存。这没什么区别。我正在清除列表中的所有项目,并为list对象分配空值。

我也尝试过用声明字节数组来代替list<Bitmap>SqlConnection对象。

但是,它并没有显示出两种方法(简单声明和using语句)之间分配的总内存有任何差异。

long l1 = GC.GetTotalMemory(true);
//SqlConnection cnn = new SqlConnection("");    //1st Method
using (SqlConnection cnn = new SqlConnection("")) //2nd Method
{
//nothing to do
}
long l2 = GC.GetTotalMemory(false);
Console.WriteLine(l1.ToString());
Console.WriteLine(l2.ToString());

我不明白为什么它不清除由托管对象和非托管对象分配的内存

垃圾收集器不会一直运行,而是仅在必要时运行。在我的测试中,有时它可能在5分钟内只运行一次。您可以强制垃圾收集器使用GC.Collect();GC.WaitForPendingFinalizers();进行收集

清除列表或为对象赋值null不会像C/C++free()调用那样释放内存。它只是向运行时指示您已经完成了该对象。GC(垃圾收集器)将不时运行。它将查看对象并跟踪每个对象的所有权树。如果它发现对象没有所有者,它将释放内存(将其返回到托管堆)。事实上,它比这更复杂,根据大小和用途有多个"代",但想法是一样的。在"释放"对象之前,将运行对象终结器(如果定义了终结器)。这个想法是,该系统不会花很多时间处理内存管理。。。除非迫不得已。

.NET和Java中的垃圾收集器都是在

  1. 释放内存的目的是允许它用于满足未来的分配请求
  2. 在进行垃圾收集之前等待更长时间,通常会在一定程度上增加可释放的内存量,而不是增加计算成本(从而降低平均每兆字节的分配和回收净成本)

因此,.NET和Java都不寻求在最后一个剩余引用被销毁时回收内存,而是在有机会使用回收的内存时回收内存。他们通常不会等到所有内存都被填满才这样做(由于缓存和其他因素,GC通常最好花费大部分精力反复回收一个小池),但在没有任何立即需要回收内存的情况下,找出可用内存通常没有什么好处。

最新更新