我正在从"Professional C#"一书中学习C#中的内存管理
垃圾收集器的存在意味着您通常不会担心您不再需要的物体; 您将简单地允许对这些对象的所有引用超出范围,并允许垃圾收集器根据需要释放内存.但是,垃圾收集器不知道如何释放非托管资源(例如文件句柄,网络连接和数据库连接).当托管类封装对非托管资源的直接或间接引用时,您需要进行特殊配置以确保在对类的实例进行垃圾回收时释放非托管资源.
定义类时,可以使用两种机制自动释放非托管资源.
- 将析构函数(或终结器)声明为您的类的成员.
- 在类中实现System.IDisposable接口.
我不明白一些事情:
"非托管资源(例如文件句柄,网络连接和数据库连接)".关于他们的重大事项是什么?为什么他们不受管理?(或)为什么GC不能管理这些资源?
我们将在一个类的终结器或Dispose()方法中放置什么代码以及该代码究竟是什么样的?使用这些资源的一些例子会有很多帮助.
阅读此处的答案后,我决定将我的类标记为密封,以简化IDisposable实现。为什么sealed会影响IDisposable的实现(例如GC.SuppressFinalize(this);不需要调用)?请解释发生了什么事。我需要能够向其他开发人员解释为什么我要密封该类。
在一些地方,人们建议使用private void Dispose(bool)该IDisposable模式.这似乎过时了(至少对于未密封的类),因为新建议的模式(根据微软)protected virtual void Dispose(bool).
The thing is, Code Analysis does not report private void Dispose(bool) for violating CA1063, even though it seems to violate the pattern directly.
What's up with this? Is private void Dispose(bool) somehow getting called (or compiled to something that looks like protected virtual Dispose(bool)?
If this is some issue with Code Analysis and is the incorrect pattern, are there ways to detect this? Possibly with StyleCop? …
我在我的类中实现了Finalize和Dispose,我在我的父类上实现了IDisposable并覆盖了我的子类中的Dispose(bool)重载.我不确定
这两件事都是在这里给出的例子中完成的 -
虽然此MSDN文章中的示例没有这两个中的任何一个 - http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx
而MSDN中的这个例子并不完整 - http://msdn.microsoft.com/en-us/library/ms182330.aspx
我正在为一个小项目创建一个简单的类,并决定只为快速impl添加一个析构函数而不是使用IDisposable,每当有一个带有访问修饰符的析构函数时,我就遇到了编译器错误.
public class MyClass
{
public ~MyClass()
{
// clean resources
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试过公共,私有,受保护和内部.没有访问修饰符,它工作正常.由于这篇文章显示 ~destructor本质上是一个受保护的Finalize函数的合成糖,因此我觉得奇怪的是你不能在析构函数上使用至少受保护的东西.文章确实说"无法调用析构函数.它们会被自动调用." 这是如何强制执行该行为的?
我最后只是实现IDisposable了,但我很好奇...... 还有其他原因你不能在析构函数上放置访问修饰符吗?
假设我有一个与另一个班级相关联的班级.它看起来像下面这样:
public class DisposableClassOne : IDisposable
{
private class mDisposableClassTwo;
public DisplosableClassOne(DisposableClassTwo dcTwoInjected)
{
mDisposableClassTwo = dcTwoInjected;
}
public void Dispose()
{
// Should I dispose here? or make caller dispose of dcTwoInjected
//mDisposableClassTwo.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
我应该调用Dispose方法mDisposableClassTwo还是应该让调用者像这样处理它?
using(DisposableClassTwo dcTwoInjected = new DisposableClassTwo())
using(DisposableClassOne dcOne = new DisposableClassOne(dcTwoInjected))
{
// do stuff with dcOne
}
Run Code Online (Sandbox Code Playgroud)
我正在考虑让调用者处理它是最好的方法,但我认为通过在Dispose方法中调用它可以保证它会被调用.有没有更好的方法来处理这个?
当我编写邮件传递服务时,我找到了“Dispose()”函数:
private void InnerDisposeMessage(MailMessage message)
{
if (message != null)
{
if (message.AlternateViews.Count > 0)
{
message.AlternateViews.Dispose();
}
message.Dispose();
message = null;
}
}
Run Code Online (Sandbox Code Playgroud)
我跟踪到Dispose()函数( message.AlternateViews.Dispose();),这里是:
public void Dispose()
{
if (!this.disposed)
{
foreach (AlternateView view in this)
{
view.Dispose();
}
base.Clear();
this.disposed = true;
}
}
Run Code Online (Sandbox Code Playgroud)
我跟踪到 view.Dispose() 函数,这里是:
protected virtual void Dispose(bool disposing)
{
if (disposing && !this.disposed)
{
this.disposed = true;
this.part.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
我跟踪到 this.part.Dispose(); 函数,这里是:
public void Dispose()
{
if (this.stream != …Run Code Online (Sandbox Code Playgroud) 我有这个简单的代码,并试图调用析构函数,但我不能称之为:(
我知道GarbageCollector会在必要时运行,所以我使用了GC.WaitForPendingFinalizers(); 但它也没有用.
这是我的代码:
class Program
{
static void Main(string[] args)
{
Calculator calculator = new Calculator();
Console.WriteLine("{0} / {1} = {2}", 120, 15, calculator.Divide(120, 15)
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Program finishing");
}
}
class Calculator
{
// Constructor
public Calculator()
{
Console.WriteLine("Calculator being created");
}
// Public Divide method
public int Divide(int first, int second)
{
return first / second;
}
// Destructor
~Calculator()
{
Console.WriteLine("Destructor is called");
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的输出:
正在创建的计算器
120/15 = 8
程序完成
我究竟做错了什么?为什么我看不到"析构函数被调用"?
我有一个我正在使用的第三方组件,我看到一些资源未被发布的问题.该组件导致Windows创建UDP套接字的句柄("\ Device\Udp"以及"\ Device\Afd").如果我允许程序执行和取消引用第三方对象,我认为就像我过去使用的所有.NET对象一样,该对象将被垃圾收集.但是,Process Explorer显示"\ Device\Udp"句柄被无限期保留,直到实际进程被终止(或者在有问题的应用程序中:应用程序池被回收.
此外,如果我手动调用对象的Dispose()方法,则释放句柄.这是我已经解决的问题,但我只是想知道为什么需要它.是否有可能组件的构建者已经做了某些事情或者设置了一些属性来阻止垃圾收集器调用对象的破坏?
如果有帮助,我已经发布了以下代码.代码在Forms应用程序中使用,因此在while循环完成后进程不会结束.
无法使用的代码(无限期创建100个句柄):
for (int i = 0; i < n; i++)
{
Snmpmgr mgr = new Snmpmgr();
mgr.Timeout = 10;
mgr.ObjCount = 1;
mgr.ObjId[1] = ".1.3.6.1.2.1.1.1.0";
try
{
mgr.SendGetRequest(); // Handle shows up in ProcExplorer after this call
}
catch (Exception ex)
{
throw new TimeoutException("Error contacting CMTS.");
}
} // end of for... obj referenced by mgr never garbage collected
Run Code Online (Sandbox Code Playgroud)
有效的代码(创建和释放的句柄):
for (int i = 0; i < n; i++)
{ …Run Code Online (Sandbox Code Playgroud) 微软建议的配置模式说Dispose()和终结器都应该调用虚拟的第三种方法Dispose(bool).所以它看起来像这样:
public class DisposeBase : IDisposable
{
private bool _Disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~DisposeBase()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!_Disposed)
{
if (disposing)
{
/* Get rid of managed resources */
}
/* Get rid of unmanaged resources */
_Disposed = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
派生类将覆盖Dispose(bool).我想重组它有点像这样:
public abstract class ExtendableResourceHandlerBase : IDisposable
{
private bool _Disposed = false;
/* private resources managed and unmanaged */
public void …Run Code Online (Sandbox Code Playgroud) 在线浏览一些代码时,我遇到了以下情况:
~Disposable()
{
Dispose(false);
}
Run Code Online (Sandbox Code Playgroud)
这不会产生任何编译器错误,'〜'特别做什么或为什么会出现?
c# ×9
.net ×5
idisposable ×5
destructor ×2
.net-2.0 ×1
asp.net-mvc ×1
finalize ×1
finalizer ×1
fxcop ×1
sealed ×1
sockets ×1
udp ×1
winforms ×1
wpf ×1