2016-03-05 310 views
1

我有一個C#程序,我從Excel文件中讀取數據,其中包含大約40000個數字。這是我的代碼的一部分:如何在C#中運行程序後釋放內存?

 Microsoft.Office.Interop.Excel.Application _excelApp = new   Microsoft.Office.Interop.Excel.Application(); 
     _excelApp.Visible = true; 
     string fileName = "D:\\data.xlsx"; 
     Workbook workbook = _excelApp.Workbooks.Open(fileName, Type.Missing); 
     Worksheet worksheet = (Worksheet)workbook.Worksheets[1]; 
     Range excelRange = worksheet.UsedRange; 
     Object[,] valueArray = (object[,])excelRange.get_Value(XlRangeValueDataType.xlRangeValueDefault); 
     int num = worksheet.UsedRange.Rows.Count; 
     workbook.Close(false, Type.Missing); 

     _excelApp.Quit(); 
     for (int row = 1; row <= num; ++row) 
     { 
      data1.Add(Convert.ToDouble(valueArray[row, 1])); 
      data2.Add(Convert.ToDouble(valueArray[row, 2])); 
     } 

我每次運行該程序,Excel文件出現了一會兒,被關閉。但是在windows的後臺進程中有一些打開的excel文件,並且會消耗ram並降低windows的速度。我怎樣才能完全關閉excel文件,並退出我的代碼中的內存?

謝謝。

回答

-1

要強制垃圾收集器調用,這基本上是通過調用所以GC.Collect ()實現。

當您調用GC.Collect時,GC將在單獨的線程上運行每個對象的終結器。因此,另一種要記住的方法是GC.WaitForPendingFinalizers。這種同步方法直到GC.Collect完成其工作後纔會返回。

例子:

public void MethodUsingTonsOfMemory(){ 
    // do memory intensive stuff 

    GC.Collect(); 
    GC.WaitForPendingFinalizers(); // wait for memory to be released 

    Debug.WriteLine("Memory should be clear now"); 
} 
+0

噢,你的意思是如何在後臺關閉OTHER excel文件? –

+1

我不知道爲什麼這會得到低調,調用'GC.Collect()'後跟'GC.WaitForPendingFinalizers();'是解決excel問題的正確方法。調用'FinalReleaseComObject'是做這件事的錯誤方式,但是這個答案在整個互聯網上都是猖獗的。唯一需要注意的是,如果使用COM對象的相同方法執行此操作,它將不會以調試模式收集對象,也不會收集由於調試器完成的對象生命週期擴展而連接的調試器。 –

+0

我測試了這個建議。但它沒有任何效果! – Yaser

2

你需要釋放你使用的COM對象,使他們能夠正確地關閉。

試試這個代碼:

var _excelApp = new Microsoft.Office.Interop.Excel.Application(); 
_excelApp.Visible = true; 
var fileName = "D:\\data.xlsx"; 
var workbooks = _excelApp.Workbooks; 
var workbook = workbooks.Open(fileName, Type.Missing); 
var worksheet = (Worksheet)workbook.Worksheets[1]; 
var excelRange = worksheet.UsedRange; 
Object[,] valueArray = (object[,])excelRange.get_Value(XlRangeValueDataType.xlRangeValueDefault); 
int num = worksheet.UsedRange.Rows.Count; 

Marshal.FinalReleaseComObject(excelRange); 
Marshal.FinalReleaseComObject(worksheet); 

workbook.Close(false, Type.Missing); 

Marshal.FinalReleaseComObject(workbook); 
Marshal.FinalReleaseComObject(workbooks); 

_excelApp.Quit(); 

Marshal.FinalReleaseComObject(_excelApp); 

for (int row = 1; row <= num; ++row) 
{ 
    data1.Add(Convert.ToDouble(valueArray[row, 1])); 
    data2.Add(Convert.ToDouble(valueArray[row, 2])); 
} 

我還沒有測試此代碼,但它應該是接近。

請注意,你絕對必須做這樣的代碼:

var workbooks = _excelApp.Workbooks; 
var workbook = workbooks.Open(fileName, Type.Missing); 

...你不能只是這樣做:

var workbook = _excelApp.Workbooks.Open(fileName, Type.Missing); 

...因爲這離開_excelApp.Workbooks中間對象無法釋放。

+0

Enigmativity,我認爲你比這更好地傳播錯誤的信息。調用'FinalReleaseComObject()'來解決這個問題是不正確的信息在互聯網上猖獗。請參閱[this](http://stackoverflow.com/questions/3937181/when-to-use-releasecomobject-vs-finalreleasecomobject/3938075#3938075)和[this](http://stackoverflow.com/questions/25134024/清理excel-interop-objects-with-idisposable/25135685#25135685)來自Hans Passant –

+0

我測試了這個建議。但它沒有任何效果! – Yaser

+0

@ScottChamberlain - 嗯,我在很多月前就遇到過這種情況,這是正確的做法。我不知道改變了什麼。 – Enigmativity