自动内存管理机制
在.NET Framework中,内存中的资源(即所有二进制信息的集合)分为"托管资源"和"非托管资源". 托管资源必须接受.NET Framework的CLR(通用语言运行时)的管理(诸如内存类型安全性检查),而非托管资源则不必接受.NET Framework的CLR管理.
托管资源在.NET Framework中又分别存放在两种地方: "堆栈"和"托管堆"(以下简称"堆");规则是,所有的值类型(包括引用和对象实例)和引用类型的引用都存放在"堆栈"中,而所有引用所代表的对象实例都保存在堆中。
在C#中,释放托管资源是可以自动通过"垃圾回收器"完成的.
1、 值类型(包括引用和对象实例)和引用类型的引用其实是不需要什么"垃圾回收器"来释放内存的,因为当它们出了作用域后会自动释放所占内存。
2、 只有引用类型的引用所指向的对象实例才保存在"堆"中,而堆因为是一个自由存储空间,所以它并没有像"堆栈"那样有生存期,"垃圾回收器"只对这块区域起作用;
3、 "垃圾回收器"不会立即执行(当堆中的资源需要释放时),而是在引用类型的引用被删除和它在"堆"中的对象实例被删除中间有个间隔,为什么呢? 因为"垃圾回收器"的调用是比较消耗系统资源的,因此不可能经常被调用! 用户代码可以用方法System.GC.Collect()来强制执行"垃圾回收器"。
使用类的Dispose()方法释放所有类型资源 和 使用析构方法释放非托管资源!
1.Dispose()方法,垃圾回收器并不是通过调用Dispose()方法进行资源回收的,而通过调用类的析构方法来对内存中的非托管资源进行回收的。 要通过Dispose()方法来释放资源,那么在类定义的时候执"System.IDisposable"接口,然后在类中必须包含这样定义的方法"void Dispose()" 。 (在Dispose()方法中就是用户自己写的释放资源的代码段),这样一来,用户就会知道可以通过人为地调用Dispose()方法来释放资源。
2、 析构方法, 在C#中定义析构方法的格式是" ~CLASS_NAME() ".非常需要注意的是,如果一个类中没有使用到非托管资源,那么请一定不要定义析构方法,这是因为对象执行了析构方法,那么"垃圾回收器"在释放托管资源之前要先调用析构方法,然后第二次才真正释放托管资源,这样一来,两次删除动作的花销比一次大多的!用户代码可以屏蔽垃圾回收器对析构方法的调用,使用 System.GC.SuppressFinalize(this);
代码演示
public class ResourceHolder : System.IDisposable
{
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this); // 如果用户已调用此方法,将防止"垃圾回收器"调用这个类中的析构方法。
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// 这里是清理"托管资源"的用户代码段
}
// 这里是清理"非托管资源"的用户代码段
}
//此方法由垃圾回收器进行调用
~ResourceHolder()
{
Dispose(false);
}
}
托管资源在.NET Framework中又分别存放在两种地方: "堆栈"和"托管堆"(以下简称"堆");规则是,所有的值类型(包括引用和对象实例)和引用类型的引用都存放在"堆栈"中,而所有引用所代表的对象实例都保存在堆中。
在C#中,释放托管资源是可以自动通过"垃圾回收器"完成的.
1、 值类型(包括引用和对象实例)和引用类型的引用其实是不需要什么"垃圾回收器"来释放内存的,因为当它们出了作用域后会自动释放所占内存。
2、 只有引用类型的引用所指向的对象实例才保存在"堆"中,而堆因为是一个自由存储空间,所以它并没有像"堆栈"那样有生存期,"垃圾回收器"只对这块区域起作用;
3、 "垃圾回收器"不会立即执行(当堆中的资源需要释放时),而是在引用类型的引用被删除和它在"堆"中的对象实例被删除中间有个间隔,为什么呢? 因为"垃圾回收器"的调用是比较消耗系统资源的,因此不可能经常被调用! 用户代码可以用方法System.GC.Collect()来强制执行"垃圾回收器"。
使用类的Dispose()方法释放所有类型资源 和 使用析构方法释放非托管资源!
1.Dispose()方法,垃圾回收器并不是通过调用Dispose()方法进行资源回收的,而通过调用类的析构方法来对内存中的非托管资源进行回收的。 要通过Dispose()方法来释放资源,那么在类定义的时候执"System.IDisposable"接口,然后在类中必须包含这样定义的方法"void Dispose()" 。 (在Dispose()方法中就是用户自己写的释放资源的代码段),这样一来,用户就会知道可以通过人为地调用Dispose()方法来释放资源。
2、 析构方法, 在C#中定义析构方法的格式是" ~CLASS_NAME() ".非常需要注意的是,如果一个类中没有使用到非托管资源,那么请一定不要定义析构方法,这是因为对象执行了析构方法,那么"垃圾回收器"在释放托管资源之前要先调用析构方法,然后第二次才真正释放托管资源,这样一来,两次删除动作的花销比一次大多的!用户代码可以屏蔽垃圾回收器对析构方法的调用,使用 System.GC.SuppressFinalize(this);
代码演示
public class ResourceHolder : System.IDisposable
{
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this); // 如果用户已调用此方法,将防止"垃圾回收器"调用这个类中的析构方法。
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// 这里是清理"托管资源"的用户代码段
}
// 这里是清理"非托管资源"的用户代码段
}
//此方法由垃圾回收器进行调用
~ResourceHolder()
{
Dispose(false);
}
}