【发布时间】:2023-03-07 17:09:01
【问题描述】:
我使用 C#、Winforms 和 Mysql 开发了一个销售点系统。部署后,我观察到内存大小随着时间的推移不断增加。在评估了我的代码之后,我觉得我的数据层可能是罪魁祸首。我已经使用这些方法概括了数据库调用
public static DataTable ExecQuery(string query, List<SqlParam> sp_params, string db)
{
MySqlConnection sCon = new MySqlConnection();
sCon.ConnectionString = "server=" + server + ";port=" + port + ";database=" + db + ";uid=" + user + ";pwd=" + password + ";charset=utf8;";
MySqlCommand command = new MySqlCommand();
command.CommandType = CommandType.Text;
command.Connection = sCon;
if (sp_params != null)
{
for (int i = 0; i < sp_params.Count; i++)
{
MySqlParameter sparam = new MySqlParameter();
sparam.ParameterName = sp_params[i].Name;
sparam.MySqlDbType = sp_params[i].Type;
sparam.Value = sp_params[i].Value;
command.Parameters.Add(sparam);
}
}
command.CommandText = query;
sCon.Open();
MySqlDataReader sd = command.ExecuteReader();
DataTable dt = new DataTable();
for (int fc = 0; fc < sd.FieldCount; fc++)
{
if (dt.Columns.Contains(sd.GetName(fc)))
{
dt.Columns.Add(sd.GetName(fc) + "1", sd.GetFieldType(fc));
}
else
{
dt.Columns.Add(sd.GetName(fc), sd.GetFieldType(fc));
}
}
while (sd.Read())
{
DataRow dr = dt.NewRow();
for (int fc = 0; fc < sd.FieldCount; fc++)
{
dr[fc] = sd.GetValue(fc);
}
dt.Rows.Add(dr);
}
sCon.Close();
return dt;
}
对于每个数据库调用,我们都使用这种方法。前端只需要指定参数和查询。我是否怀疑这种静态方法会导致内存问题?
更新:
刚刚在我的应用中发现了另一个漏洞:
无论在哪里使用reportviewer,LocalReport.ReleaseSandboxAppDomain() 都必须在宿主表单的formclosure 事件中调用。否则每次调用 Report 都会增加内存大小。
更新 2
在我的系统中找到了内存泄漏的实际原因。我正在使用我在 flowlayoutpanel 中添加的复杂用户控件。
我使用普通的 foreach 循环来处理每个控件。但不知何故,只处理了一半的对象。我将此 foreach 循环嵌套在一个 for 循环中,计数器作为控件的数量。
int count = flwControls.Controls.Count;
for (int i = 0; i < count; i++)
{
foreach (Control c in flwControls.Controls)
{
c.Dispose();
}
}
【问题讨论】:
-
@JoeDF 是导致泄漏的方法的静态'ness'?或代码的任何特定部分
-
该函数看起来没问题(除了缺少任何异常处理或 using/finally 子句来强制释放资源)。您分配和返回的表(
DataTable dt = new DataTable();)是否可能永远不会被释放? -
你最好在 finally 块中释放命令、数据读取器和数据表对象。
-
@stevewellens 这个数据表最终成为winform控件的数据源..它是在释放控件时释放的
-
C# 是否允许在没有异常处理的情况下创建连接?如果没有,我建议您将连接包含在 try-catch 中并在 finally 块中关闭它。