我們訪問的Excel對象是COM對象。對於COM對象(也包括介面),每次對於對象的引用(在C++中這一操作對應於ComCreateObject和QueryInterface)都會增加該對象的引用計數,釋放對象引用則會減少引用計數(在C++中對應於Release)。在C++中對象和介面的建立和引用是顯式的(需要編寫代碼),因此我們很清楚的知道哪些對象和介面應該在使用完成後釋放掉,釋放操作也是顯式的。但在C#中,建立和引用是隱式的,釋放卻需要顯式的,也即需要我們加入代碼手工釋放。在我們通過代碼提示編寫C#程式的時候,很可能並沒有意識到剛才的語句其實正在建立或引用一個COM對象或介面,因此,也不會有顯式的釋放操作。這樣一來,由於一直有未釋放的引用,Excel就一直保持在記憶體中,直到。。。。。The End of the World或我們手工殺掉它。
每調用上一篇的代碼來建立Excel Application一次,就會在工作管理員的列表中出現一個Excel.Exe,累積的結果,任誰都想得到。
可以通過以下方式釋放對象引用:
using System.Runtime.InteropServices;.......Marshal.ReleaseComObject(obj);
由於會多次用到該操作,需要寫成一個方法:
protected void releaseComObject(object obj){ try { System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); } finally { }}
Excel的N多個物件都會增加引用計數,因此,需要小心處理。一般來說,那些具有成員的對象和帶s能夠以數組訪問的對象基本上都會產生引用,如Excel.Range.Font對象和Sheets對象、Cells對象等,都需要顯式的釋放。但這樣也會產生新的問題:過於頻繁的引用對象和釋放引用,導致效能下降,如果最後再一起釋放,記憶體消耗又巨大。這種情況需要根據實際情況區別對待。
此外,由於每次都是建立Excel.Application,最後銷毀的方式操作,這樣會帶來啟動Excel的額外消耗,大概需要10秒(在我的機器上)。
也可以寫一個Singlton,由它建立一個唯一的Excel.Application執行個體,並完成資料操作,這樣會有效能和開銷上優勢。
這就留待有心人完成吧,偶懶得寫。