C# DataTable不释放内存
我有一个数据加载过程,将大量数据加载到DataTable中,然后执行一些数据处理,但每次作业完成后,DataLoader.exe(32位,内存限制为1.5G)都不会释放所有正在使用的内存 我尝试了3种释放内存的方法:C# DataTable不释放内存,c#,memory,memory-management,datatable,C#,Memory,Memory Management,Datatable,我有一个数据加载过程,将大量数据加载到DataTable中,然后执行一些数据处理,但每次作业完成后,DataLoader.exe(32位,内存限制为1.5G)都不会释放所有正在使用的内存 我尝试了3种释放内存的方法: DataTable.Clear()然后调用DataTable.Dispose()(释放约800 MB内存,但每次数据加载作业完成时,在加载3到4次数据后,仍会增加200 MB内存,因为内存不足异常总数超过1.5 G) 将DataTable设置为null(无内存释放,如果选择load
以下是我尝试测试的代码(在实际程序中,它不是递归调用的,它是由一些目录监视逻辑触发的。此代码只是用于测试。很抱歉造成混淆):
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统数据;
名称空间数据表\u内存\u测试
{
班级计划
{
静态void Main(字符串[]参数)
{
尝试
{
LoadData();
Console.ReadKey();
}
捕获(例外情况除外)
{
Console.WriteLine(例如ToString());
Console.ReadKey();
}
}
私有静态void LoadData()
{
DataTable=新的DataTable();
表.列.添加(“剂量”,类型(int));
表.列.添加(“药物”,类型(字符串));
表.列.添加(“患者”,类型(字符串));
表.列.添加(“日期”,类型(日期时间));
//填充数据表,使其占用大约1G内存。
对于(int i=0;i<1677700;i++)
{
表.Rows.Add(25,“Indocin”,“David”,DateTime.Now);
添加(50,“Enebrel”,“Sam”,DateTime.Now);
表.Rows.Add(10,“Hydrazine”,“Christoff”,DateTime.Now);
添加(21,“Combivent”,“Janet”,DateTime.Now);
表.行.添加(100,“迪兰丁”,“梅勒妮”,日期时间.现在);
}
WriteLine(“数据表加载完成:请检查内存”);
Console.WriteLine(“按0清除并处理数据表,按1将数据表设置为空,按2直接处理数据表”);
string key=Console.ReadLine();
如果(键==“0”)
{
表1.Clear();
表.Dispose();
WriteLine(“Datatable已处理,数据表行计数为{0}”,table.Rows.count);
GC.Collect();
long lMemoryMB=GC.GetTotalMemory(true/*true=Collect garbage before measurement*/)/1024/1024;//内存(兆字节)
控制台写入线(lMemoryMB);
}
否则,如果(键==“1”)
{
table=null;
GC.Collect();
long lMemoryMB=GC.GetTotalMemory(true/*true=Collect garbage before measurement*/)/1024/1024;//内存(兆字节)
控制台写入线(lMemoryMB);
}
否则,如果(键==“2”)
{
表.Dispose();
GC.Collect();
long lMemoryMB=GC.GetTotalMemory(true/*true=Collect garbage before measurement*/)/1024/1024;//内存(兆字节)
控制台写入线(lMemoryMB);
}
控制台.WriteLine(“作业完成,请检查内存”);
Console.WriteLine(“按0退出,按1加载更多数据并检查是否抛出内存异常”);
key=Console.ReadLine();
如果(键==“0”)
{
环境。退出(0);
}
否则,如果(键==“1”)
{
LoadData();
}
}
}
}
没有一种真正的方法可以强制C#释放内存,就像你在没有内存管理的代码中所做的那样。这有助于理解.NET垃圾收集器的工作原理。基本上,.NET应用程序中的内存使用会上升到触发垃圾收集的三种情况之一。我在回答以下问题时描述了该过程:
避免OutOfMemory
异常的一种方法是利用MemoryFailPoint
类,该类允许您设置一个失败点,超过该失败点将抛出UnficientMemoryException
,从而使您有机会减慢进程,直到另一个工作线程可用。我不确定这是否是您想要尝试的,但您可以:
如果在要求在函数外部重复时移动零件,则内存会正确释放(仅测试方法1(清除和处置)):
对象的内存可能在超出范围时被释放主要问题是垃圾收集器的行为会有所不同,这取决于您是在调试还是在没有调试器的情况下处于释放模式 当在调试生成或发布生成中存在调试器时,所有对象的生存期都会延长到方法的整个生存期。这意味着在完成
LoadData
方法之前,GC无法回收table
。这就是为什么您的内存一直不足
如果将程序更改为释放模式,并在不使用调试器的情况下运行它,那么只要将最后一个引用传递给对象,变量table
就会指向代码路径中的对象,该对象就有资格进行垃圾回收,并释放内存
GC在“可调试情况”期间更改其行为的原因是将调试器本身视为持有对当前执行代码范围内所有变量的引用。如果没有,您将无法在“监视”窗口中查看变量的值或在其上滑动鼠标。因此,在变量退出之前,您不能“传递对象的最后一个引用”
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace DataTable_Memory_test
{
class Program
{
static void Main(string[] args)
{
try
{
LoadData();
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadKey();
}
}
private static void LoadData()
{
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
// Fill the data table to make it take about 1 G memory.
for (int i = 0; i < 1677700; i++)
{
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
}
Console.WriteLine("Data table load finish: please check memory.");
Console.WriteLine("Press 0 to clear and dispose datatable, press 1 to set datatable to null, press 2 to dispose datatable directly");
string key = Console.ReadLine();
if (key == "0")
{
table.Clear();
table.Dispose();
Console.WriteLine("Datatable disposed, data table row count is {0}", table.Rows.Count);
GC.Collect();
long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes
Console.WriteLine(lMemoryMB);
}
else if (key == "1")
{
table = null;
GC.Collect();
long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes
Console.WriteLine(lMemoryMB);
}
else if (key == "2")
{
table.Dispose();
GC.Collect();
long lMemoryMB = GC.GetTotalMemory(true/* true = Collect garbage before measuring */) / 1024 / 1024; // memory in megabytes
Console.WriteLine(lMemoryMB);
}
Console.WriteLine("Job finish, please check memory");
Console.WriteLine("Press 0 to exit, press 1 to load more data and check if throw out of memory exception");
key = Console.ReadLine();
if (key == "0")
{
Environment.Exit(0);
}
else if (key == "1")
{
LoadData();
}
}
}
}
static void Main(string[] args)
{
try
{
string key;
do
{
LoadData();
Console.WriteLine("Job finish, please check memory");
Console.WriteLine("Press 0 to exit, press 1 to load more data and check if throw out of memory exception");
key = Console.ReadLine();
} while (key == "1");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadKey();
}
}