如何使用 IDisposable 接口销毁非托管对象?
How to destroy an un-managed object using IDisposable Interface?
我知道如何在 class 中使用 IDisposable
界面。但是,我不知道如何释放由 class 变量分配的内存?例如,在我的 class 中,我创建了一个 List<Bitmap>
,其中包含列表中的 500 个位图图像,我正在使用 dispose 方法清除此列表。但是,当我使用 GC.GetTotalMemory()
.
获取总内存时,它显示相同的结果
在这里,我创建了一个由 IDisposable
接口实现的示例 class。
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(垃圾收集器)会不时 运行。它将遍历对象并跟踪每个对象的所有权树。如果它发现对象没有所有者,它将释放内存(return 它到托管堆)。它实际上比那个复杂一点,根据大小和用途有多个 "generations",但想法是一样的。在对象为 "freed" 之前,对象终结器(如果已定义)为 运行。这个想法是系统不会花很多时间处理内存管理......除非它必须这样做。
.NET 和 Java 中的垃圾收集器的设计前提是
- 释放内存的目的是为了满足未来的分配请求;
- 在执行垃圾收集之前等待更长时间,到某个点,通常会增加它可以释放的内存量,而不是增加计算成本(从而降低平均每兆字节的净分配成本和填海)。
因此,.NET 和 Java 都不会在最后一个剩余引用被销毁时寻求回收内存,而是在有机会使用回收的内存时寻求回收内存。他们通常不会等到所有内存都被填满才这样做(由于缓存和其他因素,GC 花费大部分精力重复回收一个小池通常更好)但是在没有任何即时需要的情况下对于回收的内存,找出哪些内存可用通常没有什么好处。
我知道如何在 class 中使用 IDisposable
界面。但是,我不知道如何释放由 class 变量分配的内存?例如,在我的 class 中,我创建了一个 List<Bitmap>
,其中包含列表中的 500 个位图图像,我正在使用 dispose 方法清除此列表。但是,当我使用 GC.GetTotalMemory()
.
在这里,我创建了一个由 IDisposable
接口实现的示例 class。
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(垃圾收集器)会不时 运行。它将遍历对象并跟踪每个对象的所有权树。如果它发现对象没有所有者,它将释放内存(return 它到托管堆)。它实际上比那个复杂一点,根据大小和用途有多个 "generations",但想法是一样的。在对象为 "freed" 之前,对象终结器(如果已定义)为 运行。这个想法是系统不会花很多时间处理内存管理......除非它必须这样做。
.NET 和 Java 中的垃圾收集器的设计前提是
- 释放内存的目的是为了满足未来的分配请求;
- 在执行垃圾收集之前等待更长时间,到某个点,通常会增加它可以释放的内存量,而不是增加计算成本(从而降低平均每兆字节的净分配成本和填海)。
因此,.NET 和 Java 都不会在最后一个剩余引用被销毁时寻求回收内存,而是在有机会使用回收的内存时寻求回收内存。他们通常不会等到所有内存都被填满才这样做(由于缓存和其他因素,GC 花费大部分精力重复回收一个小池通常更好)但是在没有任何即时需要的情况下对于回收的内存,找出哪些内存可用通常没有什么好处。