DataTable 作为参数和 return 值会导致内存泄漏吗?
Can DataTable as parameter and return value cause a memory leak?
如标题所示,我想知道使用 DataTable(或任何 object-type)作为参数或 return 值是否会导致内存泄漏?假设我有 3 个不同的函数:
public DataTable InitDT()
{
//Create and Initializes the dataTable columns, and returns a DataTable
DataTable dt = new DataTable();
DataColumn column = new DataColumn();
column.ColumnName = "Id";
dt.Columns.Add(column);
return dt;
}
public DataTable PopulateDT()
{
//Populate an Initialized DataTable and return it
DataTable dt = InitDT();
DataRow row;
row = dt.NewRow();
dt.Rows.Add(row);
return dt;
}
public void ReadDT()
{
//Read return DataTable
DataTable dt = PopulateDT();
foreach (DataRow r in dt.Rows)
{
txtId.text = r[0].ToString();
}
dt.Dispose();
}
在我的代码中,只有最后一个函数调用 dt.Dispose();
,所以我想知道之前创建的 2 个数据表会发生什么。垃圾收集器是否已经清理了它们?
1) 严格来说,在 C# 中不会出现内存泄漏。
这需要一些解释:
首先,假设您纯粹处理托管代码。如果您的 C# 连接到任何非托管代码,那么您可能会在那里发生内存泄漏,但不会在 C# 本身中发生。这里没有非托管代码。
其次,C# 程序当然可以释放比应有的更少的内存,但严格来说这不是内存泄漏。当程序丢失了对内存的所有引用,但内存仍然被分配时,就会发生内存泄漏。这在 C# 中是不可能发生的。可能发生的情况是您不小心保留了不需要的引用(例如,在 List
中填写引用而不清除已完成的引用)。同样,这里没有发生这种情况。
第三,Dispose
的目的不是清理内存,而是清理除内存以外的资源,例如文件句柄、数据库连接和非托管资源(见上文)。
因此,如果缺少 Dispose
,您可能会发生资源泄漏,但不会发生内存泄漏。
2) 是否发生资源泄漏取决于上下文
ReadDT
是自包含的——它(间接)创建和处理 DataTable
和 return 什么都没有。唯一的问题是应该有一个 using
块来调用 Dispose
以保证在抛出异常时调用它。
其他两种方法都创建(直接或间接)一个 DataTable
和 return 它。他们没有 Dispose
它是正确的,因为如果他们这样做了,他们就会 return 处理一个对象,任何人都不应该使用它。
一般规则是,如果一个方法创建并 returns 一个一次性对象,则假定调用者有责任处置它(如 ReadDT
中所做的那样)或者将责任推迟到其他地方,通常是通过 returning 对象,就像其他两种方法所做的那样。
不会有任何内存泄漏,因为 ADO.NET objects use no unmanaged resources。
DataTable
的Dispose
方法继承自MarshalByValueComponent
,对DataTable
没有任何作用。
如标题所示,我想知道使用 DataTable(或任何 object-type)作为参数或 return 值是否会导致内存泄漏?假设我有 3 个不同的函数:
public DataTable InitDT()
{
//Create and Initializes the dataTable columns, and returns a DataTable
DataTable dt = new DataTable();
DataColumn column = new DataColumn();
column.ColumnName = "Id";
dt.Columns.Add(column);
return dt;
}
public DataTable PopulateDT()
{
//Populate an Initialized DataTable and return it
DataTable dt = InitDT();
DataRow row;
row = dt.NewRow();
dt.Rows.Add(row);
return dt;
}
public void ReadDT()
{
//Read return DataTable
DataTable dt = PopulateDT();
foreach (DataRow r in dt.Rows)
{
txtId.text = r[0].ToString();
}
dt.Dispose();
}
在我的代码中,只有最后一个函数调用 dt.Dispose();
,所以我想知道之前创建的 2 个数据表会发生什么。垃圾收集器是否已经清理了它们?
1) 严格来说,在 C# 中不会出现内存泄漏。
这需要一些解释:
首先,假设您纯粹处理托管代码。如果您的 C# 连接到任何非托管代码,那么您可能会在那里发生内存泄漏,但不会在 C# 本身中发生。这里没有非托管代码。
其次,C# 程序当然可以释放比应有的更少的内存,但严格来说这不是内存泄漏。当程序丢失了对内存的所有引用,但内存仍然被分配时,就会发生内存泄漏。这在 C# 中是不可能发生的。可能发生的情况是您不小心保留了不需要的引用(例如,在 List
中填写引用而不清除已完成的引用)。同样,这里没有发生这种情况。
第三,Dispose
的目的不是清理内存,而是清理除内存以外的资源,例如文件句柄、数据库连接和非托管资源(见上文)。
因此,如果缺少 Dispose
,您可能会发生资源泄漏,但不会发生内存泄漏。
2) 是否发生资源泄漏取决于上下文
ReadDT
是自包含的——它(间接)创建和处理 DataTable
和 return 什么都没有。唯一的问题是应该有一个 using
块来调用 Dispose
以保证在抛出异常时调用它。
其他两种方法都创建(直接或间接)一个 DataTable
和 return 它。他们没有 Dispose
它是正确的,因为如果他们这样做了,他们就会 return 处理一个对象,任何人都不应该使用它。
一般规则是,如果一个方法创建并 returns 一个一次性对象,则假定调用者有责任处置它(如 ReadDT
中所做的那样)或者将责任推迟到其他地方,通常是通过 returning 对象,就像其他两种方法所做的那样。
不会有任何内存泄漏,因为 ADO.NET objects use no unmanaged resources。
DataTable
的Dispose
方法继承自MarshalByValueComponent
,对DataTable
没有任何作用。