DataTable.NewRow 內存泄漏問題
昨天做了一個自動生成Insert 語句的小工具,今天測試發現存在嚴重的內存泄漏問題,代碼看了好幾遍,沒發現問題。后來用 .Net Memory Profiler 跟蹤(跟蹤方法見 用 .NET Memory Profiler 跟蹤.net 應用內存使用情況--基本應用篇) 發現有數千個DataRow 沒有釋放,最后定位是DataTable.NewRow 的問題。
先看一下有問題的代碼
public DataRow GetNextRow() { if (_DataReader.Read()) { DataRow row = _SchemaTable.NewRow(); foreach (DataColumn col in _SchemaTable.Columns) { row[col.ColumnName] = _DataReader[col.ColumnName]; } return row; } else { return null; } }
這段代碼我希望通過SqlDataReader 對象 _DataReader 來獲取一行數據。_SchemaTable 是一個DataTable 對象,這個DataTable對象沒有記錄,只存放Table 的Schema。乍一看好像沒有什么問題,_SchemaTable.NewRow() 是根據_SchemaTable 的列信息生成一個新行,但這個新行并沒有調用 _SchemaTable.Rows.Add 方法加入到_SchemaTable 表中,一般認為這個新生成的 DataRow 在使用完后會被自動回收,但實際情況并不是這樣,只要_SchemaTable 不釋放,_SchemaTable.NewRow 生成的所有DataRow都無法釋放。
網上搜了一下,有一位仁兄和我遇到同樣問題 Table NewRow() Causes Memory Leak
被采納的解決意見是這樣的:
DataTable.NewRow() adds the created row to the DataTable's RecordManager. I am not entirely sure why this happens, but this is why it is not freed by the GC.
It appears that there are only two ways to get rid of the DataRow:
- Add it to the table, then delete it.
- Call DataTable.Clear().
也就是說DataTable.NewRow 方法創建的DataRow 對象會被加入到DataTable 的 RecordManager 中,我們可以通過以下兩種方法來釋放掉它:
1. 通過 DataTable.Rows.Add 方法將這一行加入到DataTable 中,然后再通過 DataTable.Rows.Remove 方法刪除它。
2. 調用 DataTable.Clear() 方法釋放。
由于我這個應用中數據表只存放架構信息,始終是空表,所有我采用了第2種方法。加入 _SchemaTable.Clear() 這一句后內存泄漏問題解決。
改正后的代碼如下:
public DataRow GetNextRow() { if (_DataReader.Read()) { DataRow row = _SchemaTable.NewRow(); foreach (DataColumn col in _SchemaTable.Columns) { row[col.ColumnName] = _DataReader[col.ColumnName]; } _SchemaTable.Clear(); return row; } else { return null; } }
不好意思,上面代碼還是有問題, _SchemaTable.Clear() 后DataRow 里面的數據都會被清空,必須在調用完新生成的DataRow后再 _SchemaTable.Clear 才行,特此更正。
留言列表