[C#] Datatable Memory Leak

這篇的源起是由於同事的程式在記憶體管理上出問題

  1. DataTable本身有記憶體上限
    • 32 bit OS = 2G
    • 64 bit OS = 4G
  2. DataTable Dispose失敗,造成Memory Leak

第一個問題是系統已確定的設計規格,這邊無法解決

第二個問題則牽扯到很多層面

以下將慢慢解說

 

我沒有直接幫同事Dubug程式

但這種問題建議可以從以下幾個方面下手檢查

  1. 執行緒與外部物件的生命週期不同,產生有問題的Reference。
  2. 參照到Unmanaged resource,且未正確釋放。
  3. 嘗試先清除資料,再對物件本身作釋放。

 

首先是執行緒(Thread)的問題

由於處理大量資料需要運算時間

為了避免主執行緒(通常是UI)停止回應

經常會額外使用新的執行緒來進行運算

這時若外部物件與執行緒的生命週期不同

執行階段時又有互相參照到物件

很容易導致有物件無法釋放

因而產生Memory Leak

需要檢查外部物件與執行緒之前互相參照的關聯性

改以static變數賦予固定的記憶體位置

或是想辦法降低兩者之間的相依性等等


 

再來是Unmanaged resource的部分

可以先了解.Net 的Garbage Collection機制

我是參考這兩篇文章:

由於DataTable並沒有Unmanaged resource

所以這邊以 Microsoft.Office.Interop.Excel作為範例

許多Excel物件都屬於Unmanaged resource

例如Workbook、Worksheet、Range、Cell等等

只要Create以上物件

都要記得進行Release的動作

例如 System.Runtime.InteropServices.Marshal.FinalReleaseComObject(obj);


 

 

接下來這段介紹治標不治本的方法

嘗試先清除資料,再對物件本身作釋放。

以DataTable為例

call DataTable.Dispose()之前

我會先使用DataTable.Clear()

這樣先確保Data能夠被GC給清除掉

就算DataTable本身若Dispose失敗

GC也能夠回收掉Data所佔的記憶體空間

 

下面兩張圖則是測試的範例結果

圖一:使用DataTable.Dispose()後,GC.Collect()仍無法回收記憶體

2016-1-4 下午 03-51-18

圖二:若先使用DataTable.Clear(),GC.Collect()則可成功回收資料空間

2016-1-4 下午 03-52-21

附註:

以上範例使用到GC.Collect(),強制執行記憶體回收

它會對整個系統的.NET物件做檢測回收的動作(效能不好)

這邊我用來Debug觀看是否成功回收記憶體

一般正常Release的程式不需使用GC.Collect()

GC機制會自己控制記憶體回收的時機

廣告

One thought on “[C#] Datatable Memory Leak

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s