使用EXCEL產生報表,再VB6時我們會使用CreateObject開始,
再以Set Nothing 結束,就OK了~
但在.NET並不是這麼簡單就可以釋放記憶體,
每執行一次,工作管理員又會產生一次EXCEL.EXE
網路上查到許多使用GC.Collect()來強制回收,
也有看到Kill Process的...
但這樣強制系統回收....總覺得這樣好像哪裡不妥,
若不到最後,我想我應該不會使用這方法去強制影響系統的運作,
而且這在Client端程式可以這樣執行,到Server端執行又不行~"~
一開始我還想說是權限問題~測了很久....

想說乾脆執行一次CreateObject,後續使用getObject重複使用該Object就好,結果...
又是Client可以,Server端不行,~"~
查到最後...是有Server.CreateObject 卻沒有 Server.GetObject

之後回歸最原始的方式,
再仔細看微軟的支援頁面,.NET 2.0之後可使用以下程式來回收記憶體
System.Runtime.InteropServices.Marshal.FinalReleaseComObject
我就從每一層結束都做FinalReleaseComObject
結果發現,只寫以下就可以釋放EXCEL.EXE的記憶體

Dim xlapp As Excel.Application = Server.CreateObject("Excel.Application")
xlapp.Quit()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlapp)
xlapp = Nothing

但只要再中間加上下列開啟檔案....

Dim xlBook As Workbook = xlapp.Workbooks.Open(wkPath & "\sample.xlsx")
xlBook.Close()
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(xlBook)
xlBook = Nothing

EXCEL.EXE就會出現在工作管理員中屹立不搖...
之後再想到根本,EXCEL的組成元素如下,
Application、Workbooks、Workbook、Worksheet、Range
所以就每一層都SET NEW 用完都做FinalReleaseComObject
每一層都需要正常開始與結束就可以正確釋放記憶體
這樣寫CODE寫得有點複雜,不過記憶體真的可以正常釋放,
只要其中一個環節沒有做到EXCEL.EXE就會在工作管理員中,

範例是讀取現有EXCEL擋,之後修改內容後關閉儲存~

Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Runtime.InteropServices.Marshal
 
Sub Excel()
    Dim xlApp As New Excel.Application
    Dim xlBooks As Excel.Workbooks = xlApp.Workbooks
    Dim xlBook = xlBooks.Open("D:\sample.xlsx")
    Dim xlSheet As Excel.Worksheet = xlBook.ActiveSheet
    Dim xlRange As Excel.Range
    xlApp.Visible = False
    xlApp.DisplayAlerts = False
    xlRange = xlSheet.Range("A1")
    xlRange.Value = 123
    FinalReleaseComObject(xlRange)
    FinalReleaseComObject(xlSheet)
    xlBook.Save()
    xlBook.Close()
    FinalReleaseComObject(xlBook)
    FinalReleaseComObject(xlBooks)
    xlApp.Quit()
    FinalReleaseComObject(xlApp)
End Sub


參考資料:http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109&#appliesto

 
~Shael

 

arrow
arrow

    shael 發表在 痞客邦 留言(0) 人氣()