C#优化内存使用:如何释放DataTable占用的内存

5

我正在优化一个大型批处理程序的内存使用。最占用内存的是不同的 DataTables。例如,我的 DataTable dataTable 使用了约 260MB 的内存。

如在线程 "What is the memory overhead of storing data in a .NET DataTable?" 的被采纳的答案中所建议的那样,我尝试将相关数据从 DataTable 中移出。这是我的代码:

GC.Collect(); // force the garbage collector to free memory
// First stop point - Total process memory (taskmanager) = 900 MB
List<ExpandoObject> expandoList = new List<ExpandoObject>();
foreach (DataRow dataRow in dataTable.Rows)
{
    dynamic expandoItem = new ExpandoObject();
    expandoItem.FieldName = dataRow["FieldName"].ToString();
    expandoList.Add(expandoItem);
}
// Second stop point - Total process memory (taskmanager) = 1055 MB
dataTable.Clear();
dataTable.Dispose();
dataTable = null;
GC.Collect(); // force the garbage collector to free memory
// Third stop point - Total process memory (taskmanager) = 1081 MB (wtf? even more!)

我使用Clear、Dispose和将其设置为null,因为在以下线程中建议这样做:Datatable.Dispose()会使其从内存中删除吗?。请看停止点的注释以查看该点的内存使用情况。我也尝试过使用using(DataTable dataTable =...),但结果是相同的。我做错了什么吗?或者,有没有更好的方法来缩小DataTable中的数据?

运行内存分析器,查看您的数据表(或其他大型对象)是否仍在被引用。 - fejesjoco
dtTest来自哪里?它是一个方法调用的参数吗?如果是,那么它仍然会被调用方法引用,因此不符合垃圾回收的条件。 - Paul Williams
它来自同一个函数。问题在于我使用任务管理器来检查内存大小。我不知道.NET中有保留内存。 - Vortex852456
1个回答

5
我终于找到了关于内存使用的这个帖子:.NET EXE memory footprint
被接受的答案如下:
TaskManager 不应该用于测量 .NET 应用程序的内存占用。当一个 .NET 应用程序启动时,它会向操作系统请求一块内存,然后将其分段成托管堆、堆栈和大对象堆。这就是 TaskManager 报告的总内存块,其中可能有或没有被 .NET 完全使用。一旦 .NET 应用程序获得了一块内存,它不会释放它,直到被操作系统要求释放,只有在操作系统确定需要更多的内存资源时才会发生这种情况。如果您想测量内存分配,需要查看各种性能监视器(PerfMon)计数器。
简而言之:任务管理器显示保留内存而非实际使用的内存。这意味着将 DataTable 设置为 null 是可行的。
可以使用垃圾回收器来获取实际使用的内存,以下是代码示例:
long memoryInMB = GC.GetTotalMemory(forceFullCollection: true) / 1024 / 1024;

我在我的代码中尝试了这个方法,删除datatable后可以降低28MB的内存使用量。但提取数据从datatable到另一个容器的工作量不值得这么做 :-/

希望这篇文章能帮助到其他遇到同样问题的人。

关于GC、Dispose和Finalize的更多信息,你绝对应该查看这个答案


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接