我知道如何在类中使用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中的垃圾收集器都是在
- 释放内存的目的是允许它用于满足未来的分配请求
- 在进行垃圾收集之前等待更长时间,通常会在一定程度上增加可释放的内存量,而不是增加计算成本(从而降低平均每兆字节的分配和回收净成本)
因此,.NET和Java都不寻求在最后一个剩余引用被销毁时回收内存,而是在有机会使用回收的内存时回收内存。他们通常不会等到所有内存都被填满才这样做(由于缓存和其他因素,GC通常最好花费大部分精力反复回收一个小池),但在没有任何立即需要回收内存的情况下,找出可用内存通常没有什么好处。