.Net中对于内存的释放,一般通过.Net自有的自动垃圾回收机制来完成。但是,在实际项目中,仅仅通过自动的垃圾回收机制,不能达到预期的效果。总结了一下,主要使用了三种方式:Dispose,GC.Collect以及Marshal.ReleaseComObject。
Dispose
对于一般的Object对象,可以调用Dispose来进行释放。或者在创建对象的时候,不使用New,而是使用Using,这样在引用对象结束的时候,会自动销毁。
GC.Collect
GC.Collect的功能是,强制对所有代进行垃圾回收。
何谓代?代是指托管内存中不同的区域,对象越老位于的代越靠后,比如:第一次垃圾回收后某个对象未被回收,它可能就会从0代移动到1代,以此类推。
何谓垃圾?垃圾就是只没有任何对象再和他有引用关系,专业点说就是从这个对象开始找其引用,一直找,如果找到它正在引用一个根,那么这个就是不是垃圾,如果找不到根则这个对象就是垃圾。
何谓根?根就是指一个存储位置,包含指向某个引用类型的指针。比如静态变量,全局变量就是根,当前寄存器里面的对象就是根,还有当前调用栈上的参数,局部变量都是根。
另外,垃圾回收开始的时候当前所有线程都将被挂起,开始收集托管堆上的垃圾,收集完了还要压缩内存,然后等待垃圾回收结束以后再恢复这些线程,从这个角度来说,还是少调用垃圾回收,但是不是不能调,要视情况而定。
我用到的时机是,对于一个大数据量的DataTable,以及PopupForm的销毁,强制调用了GC.Collect。然而调用之后,不会立即释放,需要等待5~10s。
Marshal.ReleaseComObject
当使用了非托管的com对象的时候,一般需要使用Marshal.ReleaseComObject。
com使用引用计数来确定对象的生存期,com客户每次引用对象的时候,就调用IUnKnown->AddRef(),而每次释放对象的时候,就调用IUnKnown->Release(),一旦引用计数达到零,就释放对象。
在.net中允许程序员显式地自己调用com的Release方法,该方法经过.net的包装,叫做System.Runtime.InteropServices.Marshal.ReleaseComObject。
对于Excel用到的Excel.Application,流媒体用到的IGraphBuilder等Com对象,均可以通过调用Marshal.ReleaseComObjec,把引用计数减一,直至引用计数就变成了零。垃圾回收发生时,com对象就可以彻底的释放了。
另外,在大数据量的时侯,对于引用类型的参数,合理的使用 ref 或 out 也可以减小内存的消耗。