我有关于处理对象的疑问。方案如下。
在使用C#开发的桌面应用程序中,我有一个函数,其中创建的对象就像这样。
namespace Class 1
{
variables section;
....
....
Function1()
{
local variables;
try
{
Object1 obj = new Object1();
....
....
if(true)
{
....
}
else
{
**obj.Dispose();**
}
}
catch()
{}
finally
{}
}
}
执行else部分时不会释放对象。 msdn链接是
http://msdn.microsoft.com/en-us/library/system.componentmodel.component.dispose(VS.90).aspx
根据该组件应该重新使用它所使用的所有资源。
我想知道,为什么不处理这个物体。
谢谢。
帕瓦纳瓦利。答案 0 :(得分:4)
由于您的自定义对象似乎继承自System.ComponentModel.Component
,因此您需要覆盖Dispose(bool)
以处置对象的资源。尽管您的对象继承自System.ComponentModel.Component
(具有Dispose方法),但除非您对dispose方法进行编码,否则不会丢弃对象的自定义资源。 (这不是通过继承System.ComponentModel.Component
而获得的自动内容。只有System.ComponentModel.Component
基类已知的资源才会被处理掉。)
在课堂上尝试这样的事情:
protected override void Dispose(bool disposing)
{
// release your resources here
}
我们不知道您的对象上的哪些资源没有被处理掉,但无论对象如何,必须对dispose方法进行编码以便释放资源。如果在处置方法中没有处置对象的资源,则在处置它时不会处置它。
例如:
ExpensiveResource myExpensiveResource1;
ExpensiveResource myExpensiveResource2;
void Dispose()
{
// release the resources
myExpensiveResource1.Dispose();
// since there is no call to dispose of myExpensiveResource2, it is not disposed of
}
答案 1 :(得分:3)
IDisposable.Dispose
只是一个类可以选择实现的方法。该方法的内容完全由类设计者决定。为了准确理解出现了什么问题,在处理/最终确定对象时应该理解许多术语。
处理对象意味着只需调用对象的Dispose方法。对象是从该函数释放其非托管资源(文件,网络句柄,流)的惯例。如果在调用Dispose
后保留对象的引用,则除非您尝试访问已在Dispose
方法中释放的资源,否则该对象仍将主要起作用。
当.NET CLR Finalizer确定没有更多对象使用此特定对象时,最终确定一个对象,并且现在可以回收它占用的内存。程序员无法直接控制强制运行时声明对象“死”。您可以强制垃圾收集器运行,但即使这样也不建议(即您真的需要知道您正在做什么才能使用GC)。
嗯,最好的方法是在Dispose
方法中设置断点。如果您还没有源代码,可以使用this method。
没有。运行Dispose
后,CLR对象仍然存在。对象完成后,内存将释放到托管内存池。如果你确切地知道它是什么类型的资源,你可以使用第三方操作系统工具,例如Process Explorer来查看该进程是否发布了文件句柄。即使这样,释放句柄的过程与认为它被释放的操作系统之间可能存在延迟。
再次,通过在终结器中设置断点或运行内存分析器。即使终结器运行,很可能(实际上肯定是)内存不会释放到操作系统。它保留在托管内存池中,CLR运行时可以选择以后使用它。
即便如此,当内存释放到操作系统时,该过程看起来就像使用该内存一样。当感觉需要它时,操作系统需要记忆。
如果你试着通过查看它在Process Manager中消耗的内存量来弄清楚你的应用程序在做什么,我可以保证你会疯狂地尝试分析。事实上,尝试这样做与尝试使用regular expressions to parse HTML相同。
这些都没有真正回答你的问题。所以,这里有一个清单来找出你的问题,因为我们没有太多可以继续下去:
**obj.Dispose();**
?答案 2 :(得分:2)
如果没有看到你的代码,很难肯定地说,但是你可能会错误地将'Dispose'误用为c ++中的析构函数或delete
/ free
答案 3 :(得分:2)
你正在混淆处理的概念,在.NET中意味着“IDisposable
的实现,因此是Dispose ()
方法”,并保证非托管资源被释放,以及垃圾收集的概念,它由运行时处理并意味着“释放分配给对象的内存”。当您维护对任何对象的引用时,垃圾收集器不会触及它 - 因此在发生这种情况之前,不释放该对象分配的内存。
这些容易混淆的概念有两个原因:
首先,通过using
语句处理IDisposable
个对象的一般做法如下:
using (IDisposable d = new MyDisposableObject ()) {
// do whatever you need d for
}
确保在退出d
块时处理using
;但它也限制了d
到块的范围,这意味着一旦执行存在块,该对象也可以自由地进行垃圾收集(不一定是立即执行,但这既不是在这里也不是他们自己的代码不再维护对它的引用)。所以在这个(非常普遍的,应该被认为是标准的)成语中,处理在消除参考的同时发生。
其次,直接访问非托管资源的类的良好实践是实现调用Dispose ()
的终结器。当对象被垃圾收集时终结器运行,因此您可以确保不会在非托管资源上留下悬空泄漏,但如果对象从未被正确处理掉,那么您将决定何时释放非托管资源严格掌握在运行时的手中,运行时决定何时仅基于内存压力执行垃圾收集,并且对非托管资源的引用数量或类型不了解或不感兴趣。因此,在这种情况下,对象的垃圾收集会强制处理非托管资源。
如果您在某个方法上明确调用Dispose ()
,例如在您的问题中(当然假设Object1
实现IDisposable
),您仍然保留对{{obj
的引用1}},因此可以访问它的所有属性和方法。当然,这些方法或属性需要您已经处理的非托管资源当然是完全合理的,在这种情况下可能会抛出System.ObjectDisposedException
,或者Object1
的作者选择处理这些资源那种情况,但如果他们不需要你已经释放的资源,那么他们按预期运作也是完全合理的。
例如,请查看System.IO.FileStream
。处理完毕后,ReadByte ()
等操作会抛出异常,因为显然无法访问要读取的文件,但调用属性CanRead
只返回false
,是有效的和预期的。 (例如,MemoryStream
甚至可以在Dispose ()
调用之后访问数据,因为(当前)实现使用由运行时管理的缓冲区而不是像内核句柄那样的任何东西。
答案 4 :(得分:0)
首先执行“其他部分”吗?你说“如果部分”总是如此
答案 5 :(得分:0)
您应该重构您的代码,如下所示:
Function1()
{
local variables;
try
{
using (Object1 obj = new Object1())
{
....
....
if(true)
{
....
}
}
}
catch() // I hope you don't use try-catch like this in real code
{} // I hope you don't use try-catch like this in real code
finally // I hope you don't use try-catch like this in real code
{} // I hope you don't use try-catch like this in real code
}
using语句确保obj在离开作用域时始终被调用。