我的记忆在哪里?初始化数据表
本文关键字:数据表 初始化 在哪里 我的记忆 | 更新日期: 2023-09-27 18:11:05
我有1个DataGridView, 1个DataTable等应用程序
我的"execute"方法(已编辑):
private void btnRunSQL_click()
{
string strConnStr = tbConnStr.Text; // connection string from textbox
string strSQL = tbSql.Text; // query from textbox
SqlDataAdapter dataAdapter = new SqlDataAdapter(strSQL, strConnStr);
SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);
// clean memory
// dtData DataTable is declared in main form class
dtData = new DataTable();
dataAdapter.Fill(dtData);
showMemoryUsage();
}
我是这样检查内存的:
public void showMemoryUsage()
{
Process proc = Process.GetCurrentProcess();
this.Text = "Peak memory: " + proc.PeakWorkingSet64 / 1024 / 1024 + "MB";
Application.DoEvents(); // force form refresh
}
当我多次运行这个函数-它使用越来越多的内存。我正在处理非常大的数据集(1000000行),经过几个大查询,我必须重新启动我的应用程序。
运行1M行查询后,我有大约900MB的内存使用,第二次运行1100MB, 1300MB等
我认为重新初始化DataTable会释放我的内存,但它没有。所以我重新初始化BindingSource(与DataGridView连接),但它也没有帮助。最后我注释了我的BindingSource和DataGridView。
补充道:
处理DataAdapter没有帮助。
我删除了DataGridView和绑定源。于事无补。
解决方案(我合并了几个答案并创建了没有泄漏的测试应用程序)
using System;
using System.Data;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Diagnostics;
// to run this code you need form and controls:
// TextBox tbConnStr - textbox with SQL Server connection string
// TextBox tbSQL - for SQL query to run/test
// TextBox tbLog - for log display
// Button btnRunSQL with OnClick event set to proper method
// Button btnRunTest with OnClick event set to proper method
namespace Test_datatable
{
public partial class Form1 : Form
{
DataTable dt; // i need this global
public Form1()
{
InitializeComponent();
}
private void btnRunSQL_Click(object sender, EventArgs e)
{
log("Method starts.");
string strConnStr = tbConnStr.Text;
string strSQL = tbSQL.Text;
using (SqlDataAdapter da = new SqlDataAdapter(strSQL, strConnStr))
{
using (SqlCommandBuilder cb = new SqlCommandBuilder(da))
{
if (dt != null)
{
dt.Clear();
dt.Dispose();
log("DataTable cleared and disposed.");
}
dt = new DataTable();
da.Fill(dt);
log("DataTable filled.");
}
}
log("Method ends.");
tbLog.Text += Environment.NewLine;
}
// prints time, string and memory usage on textbox
private void log(string text)
{
tbLog.Text += DateTime.Now.ToString()
+ " " + text + memory() +
Environment.NewLine;
Application.DoEvents(); // force form refresh
}
// returns memory use as string, example: "Memory: 123MB"
private string memory()
{
Process proc = Process.GetCurrentProcess();
return " Peak memory: " + (proc.PeakWorkingSet64 / 1024 / 1024).ToString() + "MB ";
}
// test method for 10 runs
private void btnRunTest_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
btnRunSQL_Click(new object(), new EventArgs());
}
}
}
}
最好的猜测:仍然存在通过绑定从GUI到旧数据表的链接。但是实际的代码丢失了。
在这种情况下,我的首选方法:
if (bs != null) bs.Clear(); // most likely solution
if (dtData != null) dtData.Clear(); // won't hurt
dtData = new DataTable();
bs = new BindingSource();
对于初学者,您应该处理:
private void btnRunSQL_click()
{
string strConnStr = tbConnStr.Text; // connection string from textbox
string strSQL = tbSql.Text; // query from textbox
using(SqlDataAdapter dataAdapter = new SqlDataAdapter(strSQL, strConnStr))
{
using(SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter))
{
// clean memory
// dtData DataTable and BindingSource bs are declared in main form class
dtData = new DataTable();
bs = new BindingSource();
dataAdapter.Fill(dtData);
}
}
}
但我相信你的问题至少有一部分包含在你没有给我们看的代码中。
编辑:请告诉我们你是如何使用BindingSource的。EDIT2:您正在使用PeakWorkignSet64,您的应用程序运行为64位吗?如果不是,这个属性将不准确。另外,试试System.GC.GetTotalMemory(true)
,告诉我们它报告了什么。
SqlDataAdapter和SqlCommandBuilder是一次性的,您可以尝试这样做
private void btnRunSQL_click()
{
string strConnStr = tbConnStr.Text; // connection string from textbox
string strSQL = tbSql.Text; // query from textbox
using(var dataAdapter = new SqlDataAdapter(strSQL, strConnStr))
using(var commandBuilder = new SqlCommandBuilder(dataAdapter)) {
dtData = new DataTable();
bs = new BindingSource();
dataAdapter.Fill(dtData);
}
}
我认为这不会解决您的内存问题,但由于SqlDataAdapter和SqlCommandBuilder是一次性的,这是一个好主意,这样做
你为什么不重新填充你的旧dtData
呢?
通过创建dtData
的新实例,旧的实例将在某个时间被垃圾收集器清除。您也可以手动调用GC,但如果有更好的解决方案,我不建议这样做。
编辑:为了更清楚,尝试使用这个函数:
private void btnRunSQL_click()
{
string strConnStr = tbConnStr.Text; // connection string from textbox
string strSQL = tbSql.Text; // query from textbox
using(SqlDataAdapter dataAdapter = new SqlDataAdapter(strSQL, strConnStr))
{
using(SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter))
{
// edited after comment of Jon Senchyna
dtData.Clear();
dataAdapter.Fill(dtData);
}
}
}