我们是否需要将自定义 class 的对象设置为 null,否则 GC 会处理它
Do we need to set object of custom class as null or GC will take care of it
请查看下面给出的示例代码。我有两个问题:
1. 我们需要在返回之前关闭数据 reader 还是 GC 会处理它?
2. 在这两种情况下,我们是否需要将自定义 class 对象设置为 null 或 GC 会处理它?
public class Database
{
public string DoSomething()
{
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("Select ID,Name From Person", con))
{
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
return reader["Name"].ToString();
//will this close reader once string is returned or we have to close it?
}
}
}
}
}
用法
Database database = new Database();
string res = database.DoSomething();
database = null; //is it necessary to do this or GC will take care of it?
另一个class
public class XML
{
public void ReadXML()
{
XmlDocument doc = new XmlDocument();
doc.Load("somefile.xml");
}
}
用法
XML xml = new XML();
xml.ReadXML();
xml = null; //is it necessary to do this or GC will take care of it?
TL;DR
您在 SqlReader
处缺少 using
语句。其他场景由 GC 处理。如果您完成了实现 IDisposable
接口的对象,请始终使用 Dispose
或 using
(最后一条注释中有一些例外)。
注:
有关生命周期和范围的 "subtitle" 差异,请参阅@Damien_The_Unbeliever 的评论。有关垃圾回收的更多信息,请参阅 MSDN:https://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx
一般来说,所有没有未完成引用的托管对象都将由 GC 处理。所以一般来说,你不需要显式地将它们设置为空。
但是,如果一个对象实现了 IDisposable
接口,当您使用完该对象时,最好调用 Dispose
。尽管(如果正确实施),这也会在 Finalize
调用期间调用,但最好显式调用 Dispose
(或通过 using
语句)。数据库连接、图形对象或网络连接等对象可能会导致连接池已满或占用图形内存。
请注意,这都是关于范围和未完成的引用。
如果你有这样的方法,object
"behind" database
将在它离开范围后立即得到处理,因为没有其他变量引用此方法对象:
public void Foo()
{
Database database = new Database();
string res = database.DoSomething();
//you don't need this call
// because the will be no outstanding references after the method exits.
//database = null;
}
但如果包含对象是静态的或以其他方式保持活动状态,您就会遇到这种情况;只要在某处存在对 that FooClass
object:
的有效引用,database
就会保持活动状态
public class FooClass
{
Database database = new Database();
public void Foo()
{
//some operation
}
}
如果成员实现 IDisposable
,最好通过 using
语句或显式 (Dispose()
) 调用它。虽然 GC 应该处理这个问题,尤其是第三方库,但它需要 IDisposable
才能正确实现。如果您看到这个示例,您会发现它可能很棘手,因此在面临内存泄漏时值得怀疑。
Proper use of the IDisposable interface
因此,回答您问题的情景:
在下文中,using
语句等同于 try, catch finaly
块。参见 https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/keywords/using-statement
public class Database
{
public string DoSomething()
{
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("Select ID,Name From Person", con))
{
//note: using a using here as well
using (SqlDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
{
//this is ok, because the USING will take care of the disposure.
return reader["Name"].ToString();
}
}
}
}
}
}
到目前为止,我认为这些信息足以回答有关 GC 的问题。不过有一点需要注意;如果您面临 非托管对象 ,则还需要进行其他调用才能正确处理。 COM
例如需要 Marshall.ReleaseComObject()
,并且一些库(我知道的一些工业相机驱动程序)需要显式的 CleanUp
调用。
请查看下面给出的示例代码。我有两个问题:
1. 我们需要在返回之前关闭数据 reader 还是 GC 会处理它?
2. 在这两种情况下,我们是否需要将自定义 class 对象设置为 null 或 GC 会处理它?
public class Database
{
public string DoSomething()
{
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("Select ID,Name From Person", con))
{
SqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
return reader["Name"].ToString();
//will this close reader once string is returned or we have to close it?
}
}
}
}
}
用法
Database database = new Database();
string res = database.DoSomething();
database = null; //is it necessary to do this or GC will take care of it?
另一个class
public class XML
{
public void ReadXML()
{
XmlDocument doc = new XmlDocument();
doc.Load("somefile.xml");
}
}
用法
XML xml = new XML();
xml.ReadXML();
xml = null; //is it necessary to do this or GC will take care of it?
TL;DR
您在 SqlReader
处缺少 using
语句。其他场景由 GC 处理。如果您完成了实现 IDisposable
接口的对象,请始终使用 Dispose
或 using
(最后一条注释中有一些例外)。
注: 有关生命周期和范围的 "subtitle" 差异,请参阅@Damien_The_Unbeliever 的评论。有关垃圾回收的更多信息,请参阅 MSDN:https://msdn.microsoft.com/en-us/library/0xy59wtx(v=vs.110).aspx
一般来说,所有没有未完成引用的托管对象都将由 GC 处理。所以一般来说,你不需要显式地将它们设置为空。
但是,如果一个对象实现了 IDisposable
接口,当您使用完该对象时,最好调用 Dispose
。尽管(如果正确实施),这也会在 Finalize
调用期间调用,但最好显式调用 Dispose
(或通过 using
语句)。数据库连接、图形对象或网络连接等对象可能会导致连接池已满或占用图形内存。
请注意,这都是关于范围和未完成的引用。
如果你有这样的方法,object
"behind" database
将在它离开范围后立即得到处理,因为没有其他变量引用此方法对象:
public void Foo()
{
Database database = new Database();
string res = database.DoSomething();
//you don't need this call
// because the will be no outstanding references after the method exits.
//database = null;
}
但如果包含对象是静态的或以其他方式保持活动状态,您就会遇到这种情况;只要在某处存在对 that FooClass
object:
database
就会保持活动状态
public class FooClass
{
Database database = new Database();
public void Foo()
{
//some operation
}
}
如果成员实现 IDisposable
,最好通过 using
语句或显式 (Dispose()
) 调用它。虽然 GC 应该处理这个问题,尤其是第三方库,但它需要 IDisposable
才能正确实现。如果您看到这个示例,您会发现它可能很棘手,因此在面临内存泄漏时值得怀疑。
Proper use of the IDisposable interface
因此,回答您问题的情景:
在下文中,using
语句等同于 try, catch finaly
块。参见 https://docs.microsoft.com/en-us/dotnet/articles/csharp/language-reference/keywords/using-statement
public class Database
{
public string DoSomething()
{
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("Select ID,Name From Person", con))
{
//note: using a using here as well
using (SqlDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
{
//this is ok, because the USING will take care of the disposure.
return reader["Name"].ToString();
}
}
}
}
}
}
到目前为止,我认为这些信息足以回答有关 GC 的问题。不过有一点需要注意;如果您面临 非托管对象 ,则还需要进行其他调用才能正确处理。 COM
例如需要 Marshall.ReleaseComObject()
,并且一些库(我知道的一些工业相机驱动程序)需要显式的 CleanUp
调用。