我有一个数据加载过程,将大量数据加载到DataTable中进行一些数据处理,但每次作业完成后,DataLoader.exe(32位,具有1.5G内存限制)并未释放所有已使用的内存。
我尝试了三种释放内存的方法:
- DataTable.Clear()然后调用DataTable.Dispose()(释放约800MB内存,但仍会在每次数据加载作业完成后增加约200MB内存,在3或4次数据加载后,由于总共超过了1.5G内存,将抛出内存不足异常)
- 将DataTable设置为null(没有释放内存,而且如果选择加载更多的数据,将抛出内存不足异常)
- 直接调用DataTable.Dispose()(没有释放内存,而且如果选择加载更多的数据,将抛出内存不足异常)
以下是我尝试的测试代码(在实际程序中,它不会递归调用,而是由某些目录监视逻辑触发。该代码仅用于测试。对于造成的混淆,我表示抱歉。):
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();
}
}
}
}
DataTable
本身并没有实现Dispose()
方法,它是从其父类MarshalByValueComponent
中继承的。而MarshalByValueComponent
只做了两件事情:如果你在代码示例中使用了ISite
来包含数据表,则调用Site.Container.Remove(this)
方法;并引发Disposed
事件。它不会释放任何资源。 - Scott Chamberlain