眾所周知,在.net的世界裡,程式設計師只負責使用new創建對象,而對象的銷毀則完全交給垃圾回收器負責,只有當發生垃圾回收的時候,.net中的類型才會被銷毀。這通常不會引起什麼不妥。但是,當使用了非託管的com物件的時候,則會帶來特別的問題。
com使用引用計數來確定物件的生存期,com客戶每次引用物件的時候,就呼叫
IUnKnown->AddRef(),而每次釋放物件的時候,就呼叫
IUnKnown->Release(),一旦引用計數達到零,就釋放實例。
問題就這樣產生了,讓我們來看下面的程式碼:
這是在CSDN的asp.net版廣為流傳的一段使用excel com元件匯出excel檔案到客戶端的c#程式碼,在加入這段程式碼之前,執行了新增com引用的嚮導。
Excel.Application oExcel;
Excel.Workbook oBook;
Object oMissing = System.Reflection.Missing.Value;
oExcel = new Excel.Application();
oBook = oExcel.Workbooks.Add(oMissing);
for (int i=1;i <=4;i++)
{
oExcel.Cells[i,1]=i.ToString();
oExcel.Cells[i,2]= "'bbb2 ";
oExcel.Cells[i,3]= "'ccc3 ";
oExcel.Cells[i,4]= "'aaa4 ";
}
oBook.Saved = true;
oExcel.UserControl = false;
string filename = DateTime.Now.Ticks.ToString();
string mm=Server.MapPath( ".")+ "\" + filename + ".xls";//伺服器儲存位址
oExcel.ActiveWorkbook.SaveCopyAs (mm);
oExcel.Quit();
//GC.Collect();
Response.Redirect(filename+".xls");
這段程式碼能夠實現匯出檔案的功能,但是如果察看Windows任務管理器,就會發現如下圖的精彩場面
於是,有人就在程式碼中加了一句“GC.Collect();”,很好,EXCEL.EXE沒有那麼多了,如下圖。
但是,如何能徹底釋放呢?
幸運的是,在.net中,允許程式設計師明確地自己呼叫com的Release方法,這個方法經過.net的包裝,叫做System.Runtime.InteropServices.Marshal.ReleaseComObject,在上面的程式碼中,
在呼叫“GC.Collect();”之前,先呼叫“System.Runtime.InteropServices.Marshal.ReleaseComObject((object)oExcel);”,
把引用計數減一,這樣,引用計數就變成了零,垃圾回收發生時,oExcel所對應的com對象,就被掃地出門。