我对这个类的理解是,当你想要确保调用Finalizer(析构函数)或类时,你应该使用它,但是从我做过的几个测试中,它似乎不是真的.如果它不能确保调用dispose方法,还有其他方法吗?例如,如果我想确保运行一些代码来结束我的对象,即使我通过任务管理器关闭我的程序或什么?
我一直在阅读这些关于Java终结器的幻灯片.在其中,作者描述了一个场景(在幻灯片33上),该场景CleanResource.finalize()可以由终结器线程运行,同时CleanResource.doSomething()仍然在另一个线程上运行.怎么会发生这种情况?
如果doSomething()是非静态方法,那么执行该方法某人,某处必须有一个强引用它...对吗?那么在方法返回之前如何清除这个引用呢?另一个线程可以突然进入并将该引用置空吗?如果发生这种情况,doSomething()仍会在原始线程上正常返回?
这就是我真正想知道的,但是对于一个非常超越的答案,你可以告诉我为什么doSomething()幻灯片38比doSomething()幻灯片29 更好.为什么仅仅调用这个keepAlive()方法就足够了?你不需要把整个电话包裹myImpl.doSomething()在一个synchronized(this){}街区吗?
虽然"调查"最终确定(阅读:尝试愚蠢的事情)我偶然发现了一些意想不到的行为(至少对我来说).
我原本期望Finalize方法不被调用,而它被调用两次
class Program
{
static void Main(string[] args)
{
// The MyClass type has a Finalize method defined for it
// Creating a MyClass places a reference to obj on the finalization table.
var myClass = new MyClass();
// Append another 2 references for myClass onto the finalization table.
System.GC.ReRegisterForFinalize(myClass);
System.GC.ReRegisterForFinalize(myClass);
// There are now 3 references to myClass on the finalization table.
System.GC.SuppressFinalize(myClass);
System.GC.SuppressFinalize(myClass);
System.GC.SuppressFinalize(myClass);
// Remove the reference to the object.
myClass = null;
// Force the …Run Code Online (Sandbox Code Playgroud) 主要问题在于主题,但是让我展示我对Java中最终化过程的看法,以便我可以向您提出更多要求.
那么gc通过标记所有活动对象来启动垃圾收集.当所有可到达的对象都标记为"实时"时.所有其他对象都无法访问.下一步是检查每个无法到达的对象,并确定它是否可以立即进行清理,或者应该首先完成.如果对象的finalize方法有一个主体,那么gc会想到下一个方法,那么这个对象是可以最终确定的并且应该最终确定; 如果对象的finalize方法有一个空体(protected void finalize(){})那么它不能最终化并且现在可以被gc清理.(我是对的吗?)
所有可终结的对象将放在同一个队列中,以便稍后逐一完成.据我所知,可终结的对象可以花费大量时间放在队列中,同时等待轮到他们完成.这可能发生,因为通常只有一个名为Finalizer的线程从队列中获取对象并调用它们的finalize方法,当我们在某个对象的finalize方法中有一些耗时的操作时,队列中的其他对象将等待很长时间才能完成.好的,当一个对象完成后,它被标记为FINALIZED并从队列中删除.在下一个垃圾收集过程中,收集器将看到此对象无法访问(再次)并且具有非空的finalize方法(再次),因此该对象应该被放入队列中(再次) - 但它不会因为收集器以某种方式看到这个对象被标记为FINALIZED.(这是我的主要问题:这个对象被标记为FINALIZED的方式,收集器如何知道该对象不应该再次终结?)
我有一个类(比如说MyClass)使用(作为私有字段)一个TcpClient对象.MyClass实现IDisposable调用TcpClient.Close的Dispose方法.
我的问题是MyClass还应该实现一个终结器来调用Dispose(bool Disposing)释放TcpClient’s非托管资源,以防MyClass.Dispose调用代码没有调用?
谢谢
一旦变量失去.Net语言的范围,有没有办法"自动"运行终结/析构函数代码?在我看来,由于垃圾收集器在不确定的时间运行,因此一旦变量失去范围,析构函数代码就不会运行.我意识到我可以从IDisposable继承并在我的对象上显式调用Dispose,但我希望可能有更多不干涉的解决方案,类似于non.Net C++处理对象破坏的方式.
期望的行为(C#):
public class A {
~A { [some code I would like to run] }
}
public void SomeFreeFunction() {
SomeFreeSubFunction();
// At this point, I would like my destructor code to have already run.
}
public void SomeFreeSubFunction() {
A myA = new A();
}
Run Code Online (Sandbox Code Playgroud)
不太理想:
public class A : IDisposable {
[ destructor code, Dispose method, etc. etc.]
}
public void SomeFreeFunction() {
SomeFreeSubFunction();
}
public void SomeFreeSubFunction() {
A myA = new A();
try { …Run Code Online (Sandbox Code Playgroud) 来自Effective Java:
哦,还有一件事:使用终结器会有严重的性能损失.在我的机器上,创建和销毁一个简单对象的时间约为5.6 ns.添加终结器可将时间增加到2,400 ns.换句话说,使用终结器创建和销毁对象的速度大约低430倍.
是什么让终结者如此昂贵?
如何定义在类定型期间存储'this'的代码?垃圾收集器应该如何表现(如果在某处定义)?
在我看来,GC应该多次完成类实例,并且以下测试应用程序将打印"66",但终结器只执行一次,导致应用程序打印"6".
几行代码:
using System;
namespace Test
{
class Finalized
{
~Finalized()
{
Program.mFinalized = this;
}
public int X = 5;
}
class Program
{
public static Finalized mFinalized = null;
static void Main(string[] args)
{
Finalized asd = new Finalized();
asd.X = 6;
asd = null;
GC.Collect();
if (mFinalized != null)
Console.Write("{0}", mFinalized.X);
mFinalized = null;
GC.Collect();
if (mFinalized != null)
Console.Write("{0}", mFinalized.X);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我要做的是了解终结器如何管理实例内存.在我的应用程序中可能希望再次重用实例引用以进行进一步处理.
很明显终结器不会"释放"内存(至少在我的测试应用程序中).可以将内存块重用于其他目的吗?甚至解放了?如果不是,那会是内存泄漏还是什么?
现在,我比以前更困惑了.
我非常熟悉非终结类型的Dispose模式,例如,包含我们想要进行确定性清理的某种托管资源的类型.这些类型通常不实现终结器,因为它完全没有必要.
但是,我正在为本机API实现一个C#包装器,其中包含多个相关的非托管资源,并且看起来需要多个类,每个类都实现了finalizable-dispose模式.问题是配置模式的指导方针说最终的A不应该依赖于最终的B,这正是我需要的:
X不要在终结器代码路径中访问任何可终结的对象,因为它们已经完成的风险很大.
例如,具有对另一个可终结对象B的引用的可终结对象A不能在A的终结器中可靠地使用B,反之亦然.终结器以随机顺序调用(缺少关键终结的弱排序保证).
所以这是我的约束:
本机API看起来像这样:
APIHANDLE GizmoCreateHandle();
CHILDHANDLE GizmoCreateChildHandle( APIHANDLE apiHandle );
GizmoCloseHandle( APIHANDLE apiHandle );
GizmoCloseChildHandle( APIHANDLE apiHandle, CHILDHANDLE childHandle);
Run Code Online (Sandbox Code Playgroud)
对此的天真方法将分为两部分:
所以一切都看起来像这样:
[DllImport( "gizmo.dll" )]
private static extern ApiSafeHandle GizmoCreateHandle();
[DllImport( "gizmo.dll" )]
private static extern void GizmoCloseHandle( IntPtr apiHandle );
[DllImport( "gizmo.dll" )]
private static extern ChildSafeHandle GizmoCreateChildHandle(ApiSafeHandle apiHandle);
[DllImport( "gizmo.dll" )]
private static extern void GizmoCloseChildHandle( ApiSafeHandle apiHandle, IntPtr childHandle );
[DllImport( "gizmo.dll" …Run Code Online (Sandbox Code Playgroud) 根据Essential C#6.0,你应该:
AVOID在拥有终结器的拥有对象上调用Dispose().相反,依靠终结队列来清理实例.
Finalizer?Close()/ Close()+ Dispose()?对于非常具体的类型(MemoryStream/ Form/ SqlConnection/ etc),我在网络上看到了很多问题,但我更关注"如何自己解决".根据Dispose Pattern你应该:
除了Dispose()之外,CONSIDER提供方法Close(),如果close是该区域中的标准术语.这样做时,将Close实现与Dispose相同并考虑显式实现IDisposable.Dispose方法非常重要.
但有时候你应该像两个人一样打电话Form等.像" 关闭和处理 - 要打电话的人? "这样的问题越来越接近,但除此之外没有明确的方法
像往常一样答案是:这取决于.不同的类以不同的方式实现IDisposable,由您来做必要的研究.
编辑:这是完整的指南,我没有要求复制许可,但因为它是一个指南(因此假设它应该是自由共享的公共知识)而不是实际培训材料的某些部分,我希望我'我没有违反任何规则.
准则
DO仅对具有稀缺或昂贵资源的对象实施终结器方法,即使最终化延迟了垃圾收集.
实现IDisposable以支持具有终结器的类的确定性终结.
如果没有显式调用Dispose(),请对实现IDisposable的类实现终结器方法.
DO重构一个finalization方法来调用与IDisposable相同的代码,也许只是调用Dispose()方法.
不要从终结器方法中抛出异常.
从Dispose()调用System.GC.SuppressFinalize()以避免重复资源清理并延迟对象上的垃圾回收.
确保Dispose()是幂等的(应该可以多次调用Dispose()).
保持Dispose()简单,专注于最终化所需的资源清理.
AVOID在拥有终结器的拥有对象上调用Dispose().相反,依靠终结队列来清理实例.
避免引用在最终确定期间未完成的其他对象.
在重写Dispose()时,请调用基类的Dispose()方法.
在调用Dispose()之后,考虑确保对象变得不可用.在处理了一个对象之后,Dispose()以外的方法(可能被多次调用)应抛出一个ObjectDisposedException.
在具有一次性字段(或属性)的类型上实现IDisposable并处理所述实例.
finalizer ×10
c# ×6
.net ×3
java ×3
dispose ×2
idisposable ×2
.net-2.0 ×1
.net-4.0 ×1
clr ×1
destructor ×1
finalization ×1
finalize ×1
pinvoke ×1
vb.net ×1