C#中的垃圾回收
简单说一下C#中的内存管理、垃圾回收和资源管理
为什么需要垃圾回收
我们每次在C#中创建一个对象(Object),CLR都会在堆中给Object分配一块内存,但是系统内存总有用完的时候,这是就需要清理一些用过的内存
CLR会判断所有创建出来的对象中,那些不会再被程序用到,然后把它们销毁。
任何进程被触发后,都会从物理内存中分配到一块虚拟空间,程序处理的也是虚拟空间而不是物理内存。GC分配和回收内存时,处理的也是虚拟空间
GC工作机制
当GC被激活时,它会找出不再使用的对象(已经死亡的对象,也就是所谓的垃圾),然后对仍然在使用的对象进行压缩并尝试释放内存。
一般情况下,堆(heap)被分为三代(Generation),并根据对象在内存中的存活时间进行存储和处理。三代堆的区别如下:
0代:存储在内存中存活时间最短的对象,如一些临时性的对象(temporary object),在此代中垃圾处理的频率最高
1代:0代和2代堆之间的一个缓存
2代:存储在内存中存活时间最长的对象,比如静态static或全局global变量。
在0代中的对象如果没有被回收,它将会被移至1代中,同样,如果对象在1代中没有被回收,它将被移至2代中。
GC运行过程
首先要说一下“根”的概念,一个根可以是:
一个正在制定的方法的局部变量或参数
一个静态变量
存储在结束队列中的一个对象
一次垃圾回收过程开始时,GC会认为堆中的所有对象都是垃圾。
GC检查所有的对象,当一个对象被根引用了,那么对这个对象进行标记。当所有的对象都被遍历后,没被标记过的对象就是垃圾对象,应该进行回收。
垃圾回收时,先释放垃圾对象所占用的内存,然后把未回收的对象移到这里来压缩堆(当然移动后对象的位置改变了,所有对象的引用也要重新修正)
托管资源(Managed Source)和非托管资源(Unmanaged Source)
所有CLR创建并管理的均为托管资源,如string、bool等类型的变量
在.net库外创建而且无法被CLR管理的均为非托管资源,比如COM对象,FileStream,Interop对象等。
回收非托管资源
当我们创建了一个非托管对象时,当我们使用完这些非托管对象(例如Filestream、database connection、network instance等),GC是无法意识到它们已经成为了垃圾。
清理非托管资源的方法是实现IDisposable借口和Dispose方法,实现Dispose方法有2个途径
使用SafeHandle类实现Dispose
重写Object.Finalize方法
通过SafeHandle类实现Dispose
class clsDispose_safe
{
// Take a flag to check if object is already disposed
bool bDisposed = false;
// Create a object of SafeHandle class
SafeHandle objSafeHandle = new SafeFileHandle(IntPtr.Zero, true);
// Dispose method (public)
public void Dispose1()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Dispose method (protected)
protected virtual void Dispose(bool bDispose)
{
if (bDisposed)
return;
if (bDispose)
{
objSafeHandle.Dispose();
// Free any other managed objects here.
}
// Free any unmanaged objects here.
//
bDisposed = true;
}
}
通过重写Object.Finalize方法实现Dispose
class clsDispose_Fin
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose1(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose1(bool disposing)
{
if (disposed)
return;
if (disposing)
{
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
}
~clsDispose_Fin()
{
Dispose1(false);
}
}