艾伟_转载:DataTable.NewRow 内存泄漏问题

简介:   昨天做了一个自动生成Insert 语句的小工具,今天测试发现存在严重的内存泄漏问题,代码看了好几遍,没发现问题。后来用 .Net Memory Profiler 跟踪(跟踪方法见 用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇) 发现有数千个DataRow 没有释放,最后定位是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:

  1. Add it to the table, then delete it.
  2. 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 才行,特此更正。

目录
相关文章
|
3月前
|
存储 编译器 Linux
【内存管理大猫腻:从“越界”到“内存泄漏”应有尽有】
【内存管理大猫腻:从“越界”到“内存泄漏”应有尽有】
|
4月前
|
存储 Linux C语言
手撕检测内存泄漏组件
手撕检测内存泄漏组件
22 0
|
9月前
|
C++
|
4月前
|
C语言 C++
【C++干货铺】内存管理new和delete
【C++干货铺】内存管理new和delete
|
8月前
cocoscreator查内存泄露,绘制内存监视器
cocoscreator查内存泄露,绘制内存监视器
154 0
JVM垃圾回收器详解:不同的复制算法比较及对程序员的启迪
前面提到整个JVM中只有串行回收按照Cheney的设计实现新生代回收,其他的垃圾回收器在新生代回收时都对Cheney的复制算法进行了增强。 其中最大的改变就是不使用宽度优先,而是使用深度优先的处理方式。其中Moon在1984年提出了一种近似深度优先遍历的处理方式,称为层次遍历,使用层次遍历大概可以将GC效果提升6%。
|
存储 Java 程序员
程序员脱单秘籍 | 我跟JVM搞对象!【深度剖析对象的创建和内存分配】
程序员脱单秘籍 | 我跟JVM搞对象!【深度剖析对象的创建和内存分配】
116 0
程序员脱单秘籍 | 我跟JVM搞对象!【深度剖析对象的创建和内存分配】
|
缓存 监控 算法
啥?小胖连 JVM 对锁做了那些优化都不知道?真的菜!
JDK1.6 之前,synchronized 一直被认为是重量级锁。而在 JDK1.6 之后,JVM 对 synchronized 内置锁的性能进行了很多优化,包括「自适应的自旋锁、锁消除、锁粗化、偏向锁、轻量级锁」等等。加了这些优化之后,synchronized 锁的性能得到了大幅度的提升,下面我们来瞧瞧到底咋回事?
啥?小胖连 JVM 对锁做了那些优化都不知道?真的菜!
|
监控 算法 安全
面经手册 · 第27篇《JVM 判断对象已死,实践验证GC回收》
先动手验证垃圾回收 JVM 垃圾回收知识框架 1. 判断对象已死 2. 垃圾回收算法 3. 垃圾回收器
197 0
面经手册 · 第27篇《JVM 判断对象已死,实践验证GC回收》
|
存储 缓存 监控
来来来,聊聊7种内存泄露场景和13种解决方案
来来来,聊聊7种内存泄露场景和13种解决方案
276 0
来来来,聊聊7种内存泄露场景和13种解决方案