using System;
public class A
{ ~public A()
{
Console.WriteLine("Destructor instance of A");
} public void F()
{
Console.WriteLine("Call A.F()");
Test.a = this;
}
}public class B
{
private A a = null; public void SetA(A a)
{
this.a = a;
}
~public B()
{
Console.WriteLine("Destructor instance of B");
a.F();
}
}
public class Test
{
public static A a = null;
public static B b = null; static void Main()
{
b = new B();
a = new A();
b.SetA(a);
b = null;
a = null;
GC.Collect();
GC.WaitForPendingFinalizers();
if(a != null)
Console.WriteLine("a is not null");
}
}当垃圾回收器首先执行A的析构函数的时候,有以下的输出:
Destructor instance of A
Destructor instance of B
Call A.F()
当执B的析构函数时可能使本来没有被引用的A的实例现在被Test.a进行引用,致使B对象符合回收条件而A不具备回收条件。
问题:
A的析构函数不是首先被调用的吗?难道对象被析构后在其他范围内还可以被引用吗?(包括在其他析构函数中或程序入口点中)
对象在析构后不是等待垃圾回收器进行内存回收吗?难道说由于B的析构函数是的Test.a引用了A的实例,将A对象至于活动的。
所以A的析构函数执行后还可以正常使用,对A来说执行析构函数后A收到影响了吗?请您详细的解释一下!
public class A
{ ~public A()
{
Console.WriteLine("Destructor instance of A");
} public void F()
{
Console.WriteLine("Call A.F()");
Test.a = this;
}
}public class B
{
private A a = null; public void SetA(A a)
{
this.a = a;
}
~public B()
{
Console.WriteLine("Destructor instance of B");
a.F();
}
}
public class Test
{
public static A a = null;
public static B b = null; static void Main()
{
b = new B();
a = new A();
b.SetA(a);
b = null;
a = null;
GC.Collect();
GC.WaitForPendingFinalizers();
if(a != null)
Console.WriteLine("a is not null");
}
}当垃圾回收器首先执行A的析构函数的时候,有以下的输出:
Destructor instance of A
Destructor instance of B
Call A.F()
当执B的析构函数时可能使本来没有被引用的A的实例现在被Test.a进行引用,致使B对象符合回收条件而A不具备回收条件。
问题:
A的析构函数不是首先被调用的吗?难道对象被析构后在其他范围内还可以被引用吗?(包括在其他析构函数中或程序入口点中)
对象在析构后不是等待垃圾回收器进行内存回收吗?难道说由于B的析构函数是的Test.a引用了A的实例,将A对象至于活动的。
所以A的析构函数执行后还可以正常使用,对A来说执行析构函数后A收到影响了吗?请您详细的解释一下!
解决方案 »
- OCR: bad language
- 【在线等】HTTPRequest之类的 求助
- silverlight effect问题
- C#中在窗体加载时默认为当前时间真么写sql语句
- 问一个关于菜单的奇怪的问题
- 如何设置IE的代理服务器?并且检测代理服务器是否有效?
- .net环境下用C#语言如何操纵treeview这样的控件?
- 密码修改的代码怎么写?(C#+sql2000)
- 如何定义一个sqlconnection类,可以让该namespace下的其他类可以访问
- 急!在同一个form里有2个按钮,按下一个能生成若干个(个数由日期的个位数决定)label和textbox,按下另一个按钮后,希望能删掉刚才生成
- C#能不能编写程序打开我的电脑
- linux平台下的C#开发
立即销毁
调用:GC.Collect();
实现IDisposable 接口的Dispose方法
@WU:
@MZ:
你们讲的都挺明白,但是我想问在A执行玩析构函数后,执行销毁动作了吗?
如果没有的话,对Test.a来说有何影响?
当某种类型实现了 Finalize() 后,该对象将进行特殊的看待:此类型对象放置在GC的特殊位置——终结列表。
1、当进行第一次垃圾收集时,此类若没有其他引用,GC会对其进行回收,此时这些对象被认为是垃圾。进行GC.Collect 时,这些垃圾会被运送到另一个位置—— 终结可达队列。而终结可达队列,类似于全局或静态变量,会被当成一种GCRoot;
2、被放置在此队列(终结可达队列)中的对象,认为是可以访问的,因此可以认为这些对象原先被当成垃圾的对象【1中提到的对象】得到了“复活”,
3、当第一次 GC.Collect 执行后,GC会清空终结可达队列,此时【1】中的对象才是真正的垃圾。
4、等待下次执行 GC.Collect 时,【1】中对象才能完全被清理掉其次,实现了 Finalize() 的对象,微软不保证其执行顺序,即:A,B 的Finalze的执行顺序是不保证的,因此不建议在A的 Finalize中访问B,或反推。因此,在实现Finalize时,微软推荐做法是同时实现 IDisposable 和 Finalize() ,即: IDisposable模式【直接取MSDN的实例】using System;
using System.ComponentModel;// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false; // The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
} // Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true); // 【 这里的参数是 true】
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
} // Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources. 【Dispose的参数 true】
// 此时 托管对象是可以确保稳定的
component.Dispose();
} // Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
// 【Finalize 的参数 false => 只能保证非托管的是稳定的】
CloseHandle(handle);
handle = IntPtr.Zero; // Note disposing has been done.
disposed = true; }
} // Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle); // Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false); // 【 这里的参数是 false 】
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}
首先感谢您真诚的讲解,经过认真阅读您的解释后我还有一个疑问请您看到后能够给于回复,在此再次谢了!!
问题1:这里被视为垃圾的含义是不是只是当成垃圾看待,而并非为真正的垃圾?而只有当当执行GC.Collect方法时垃圾回收器将其指向该对象的指针添加到终结可达队列当中,并在执行完GC.Collect方法后清空其列表后,在下一轮垃圾回收时A对象才被认为是真正的垃圾。并且A在终结可达队列中时A对象是认为可以被访问的,所以才有了在B.Finalize方法中的将A实例引用指向了Test.a的一幕。
问题2:另外看到您取了MSDN中的例子里,执行MyResourse方法时,释放非托管资源时,是不是将对象内部的实例域以及静态域至为0或null,便是执行了析构动作呢?这里的操作和实际应用操作当中是相同的吗?
问题2:非托管资源的释放与托管资源释放不一样,即使在将非托管对象置为null 或 null,其资源也不一定能释放。这个主要是非托管的资源的资源需手动释放【主要是历史问题,dotnet 之前没有GC的原因】。
其次,将托管对象(不包括静态变量,静态变量被GC当成root,这个可以用 windbg 之类的调试器看到)置为null 或 0,并不能“马上”释放其资源,什么时间执行析构,是GC决定的,主要是如下几个条件(可能不完全,可以查找相关内容):
.0代对象充满
.显示调用GC.Collect();
.内存不足
.CLR 程序域被卸载
.CLR 停止
ps:楼主的学习精神不错,在这里能看到问这些问题的的确很少。若想更了解CLR和GC的东西,可以看看《架构设计-CLR via c#》 ,加上阅读 SSCLI2 代码。