问题标签 [finalizer]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
34451 浏览

.net - Is it safe to call an RCW from a finalizer?

I have a managed object that calls a COM server to allocate some memory. The managed object must call the COM server again to free that memory before the managed object goes away to avoid a memory leak. This object implements IDisposable to help ensure that the correct memory-releasing COM call is made.

In the event that the Dispose method is not called, I would like the object's finalizer to free the memory. The trouble is, the rules of finalization is that you must not access any reference because you don't know what other objects have already been GC'd and/or finalized before you. This leaves the only touchable object state to be fields (handles being the most common).

But calling a COM server involves going through an runtime callable wrapper (RCW) in order to free the memory that I have a cookie to stored in a field. Is that RCW safe to call from a finalizer (is it guaranteed to have not been GC'd or finalized at this point)?

For those of you not familiar with finalization, although the finalizer thread runs in the background of a managed appdomain while its running, at for those cases touching references would theoretically be OK, finalization also happens at appdomain shutdown, and in any order -- not just in reference relationship order. This limits what you can assume is safe to touch from your finalizer. Any reference to a managed object might be "bad" (collected memory) even though the reference is non-null.

Update: I just tried it and got this:

An unhandled exception of type 'System.Runtime.InteropServices.InvalidComObjectException' occurred in myassembly.dll

Additional information: COM object that has been separated from its underlying RCW cannot be used.

0 投票
3 回答
1642 浏览

.net - 测试终结器和 IDisposable

问题是如何测试对象在调用 finalize 时释放资源的事实。类的代码:

请注意,我现在并不关心 Dispose/Finalize 的正确实现,因为我想先找到测试它的方法。在这个阶段,假设如果调用 Dispose/Finalize 件, HasBeenDisposed将设置为 true 就足够了。

我写的实际测试看起来像:
UPDATED WITH WEAKREFERENCE

或我更喜欢的代码(更新后添加):

该测试失败(PASSES AFTER UPDATE)但我观察到以下(更新):

  1. GC.WaitForPendingFinalizers() 确实挂起线程并最终确定o中的实例,但前提是没有植根。为其分配 NULL 并在最终确定后使用 Wea​​kReference 获取它。
  2. 当o不保存实例时,在正确的点执行完成(析构函数)代码。

那么测试这个的正确方法是什么。我想念什么?

我想是变量o阻止了 GC 收集它。
更新:是的,这是问题所在。不得不改用弱引用。

0 投票
4 回答
2751 浏览

java - 优雅地完成 SoftReference 引用

我正在使用一个搜索库,它建议保持搜索句柄对象打开,这样可以使查询缓存受益。随着时间的推移,我观察到缓存趋于膨胀(几百兆并不断增长)并且 OOM 开始出现。没有办法强制这个缓存的限制,也没有计划它可以使用多少内存。所以我增加了Xmx限制,但这只是临时解决问题的方法。

最终我想使这个对象成为. java.lang.ref.SoftReference因此,如果系统的可用内存不足,它会释放对象并按需创建一个新对象。这会在重新开始后降低一些速度,但这是一个比 OOM 更好的选择。

我看到的关于 SoftReferences 的唯一问题是没有明确的方法可以最终确定它们的所指对象。就我而言,在销毁搜索句柄之前,我需要关闭它,否则系统可能会用完文件描述符。显然,我可以将此句柄包装到另一个对象中,在其上编写终结器(或挂钩到 ReferenceQueue/PhantomReference)然后放手。但是,嘿,这个星球上的每一篇文章都建议不要使用终结器,尤其是 - 反对使用终结器来释放文件句柄(例如Effective Java ed. II,第 27 页。)。

所以我有些不解。我是否应该小心忽略所有这些建议并继续前进。否则,还有其他可行的替代方案吗?提前致谢。

编辑#1:按照 Tom Hawtin 的建议测试了一些代码后添加了以下文本。对我来说,似乎任何一个建议都不起作用,或者我错过了一些东西。这是代码:

如果我使用-Xmx10m和 SoftReferences 运行上面的代码片段(如上面的代码),我会得到大量的is null :(打印。但是,如果我用MyReference(用 MyReference 取消注释两行并用 SoftReference 注释掉两行)替换代码,我总是会得到 OOM。

正如我从建议中了解到的那样,内部有硬引用MyReference不应该阻止物体撞击ReferenceQueue,对吧?

0 投票
5 回答
1786 浏览

c# - Object.Finalize() 覆盖和 GC.Collect()

在覆盖 Object.Finalize() 的类的存在下,我似乎无法理解 GC.Collect() 的行为。这是我的基本代码:

与我的预期相反,我只在程序终止时获得控制台输出,而不是之后GC.WaitForPendingFinalizers()

0 投票
3 回答
1632 浏览

c# - 为什么 Thread 不实现 IDisposable?

我注意到 System.Threading.Thread 实现了终结器,但没有实现 IDisposable。推荐的做法是在实现终结器时始终实现 IDisposable。Jeffrey Richter写道,该指南“非常重要,应始终毫无例外地遵循”。

那么为什么 Thread 不实现 IDisposable 呢?似乎实现 IDisposable 将是一项非破坏性更改,它将允许确定性地清理 Thread 的可终结资源。

还有一个相关的问题:既然线程是可终结的,我是否必须持有对正在运行的线程的引用以防止它们在执行期间被终结?

0 投票
3 回答
406 浏览

recursion - 状态终结/初始化活动仅在叶状态上运行

我正在尝试让我的 Windows 状态机工作流程与最终用户进行通信。我试图在 StateActivity 中实现的一般模式是:

StateInitializationActivity:向用户发送请求回答问题的消息(例如“您批准此文档吗?”),以及...的上下文...
...EventDrivenActivity:处理用户发送的答案
StateFinalizationActivity:取消消息(例如文件被撤回,不再需要批准)

如果 StateActivity 是“叶状态”(即没有子状态),这一切都可以正常工作。但是,如果我想使用状态的递归组合,它就不起作用。对于非叶状态,StateInitialization 和 StateFinalization 不会运行(我通过使用 Reflector 检查 StateActivity 源代码确认了这种行为)。EventDrivenActivity 仍在监听,但最终用户不知道发生了什么。

对于 StateInitialization,我认为解决此问题的一种方法是将其替换为 EventDrivenActivity 和零延迟计时器。我对如何处理 StateFinalization 感到困惑。

那么 - 是否有人对如何让状态最终确定活动始终运行有任何想法,即使对于非叶状态也是如此?

0 投票
9 回答
1099 浏览

c# - 为什么 java 和 c# 中有终结器?

我不太明白为什么在 java 和 c# 等语言中有终结器。AFAIK,他们:

  • 不保证运行(在java中)
  • 如果它们确实运行,它们可能会在相关对象成为最终确定的候选对象后运行任意时间
  • 并且(至少在 java 中),它们甚至会在一个类上产生惊人的巨大性能损失。

那么为什么要添加它们呢?我问了一个朋友,他咕哝着“你希望有一切可能的机会来清理数据库连接之类的东西”,但这让我觉得这是一种不好的做法。为什么你应该依赖具有上述属性的东西来做任何事情,甚至作为最后一道防线?尤其是当类似的东西被设计到任何 API 中时,所说的 API 会被嘲笑不复存在。

0 投票
4 回答
6307 浏览

c# - 析构函数和终结函数的区别?

请注意:这个问题是关于“析构函数”和“终结器”这两个词之间的术语差异及其正确用法。我只是提供了它们在 C# 和 C++/CLI 中的使用示例,以说明我问这个问题的原因。我很清楚它是如何在 C# 和 CLR 中实现的,但我问的是术语的正确使用。


在 C# 世界中,术语“析构函数”和“终结器”似乎可以互换使用,我怀疑这是因为 C# 规范使用“析构函数”一词描述了非确定性清理功能,而 CLR 文档总是使用“终结器”一词,因此在 C# 领域内,它们的含义相同。

但是,在 C++/CLI 规范中,两者之间存在区别。它允许确定性和非确定性清理,并使用术语“析构函数”表示确定性功能,使用“终结器”表示非确定性功能:

终结器提供非确定性清理。终结器是在垃圾回收期间执行的“最后机会”函数,通常在未执行析构函数的对象上执行。

此外,维基百科对析构函数终结器的描述表明析构函数和终结器是独立的概念,并支持 C++/CLI 规范对确定性术语的使用:

与析构函数不同,终结器不是确定性的。当程序显式释放对象时,将运行析构函数。相比之下,终结器在内部垃圾回收系统释放对象时执行。

问题:

  • 从计算机科学的角度来看,“析构函数”和“终结函数”之间是否存在明确定义的区别,或者术语只能根据上下文来定义?

  • 如果存在明确定义的差异,那么为什么 C# 规范会使用“错误”的术语?

0 投票
1 回答
998 浏览

c# - 为什么 AppDomain.Unload() 在终结器中出错?

这是一些示例代码:

我有一个类,它在构造函数中创建一个 AppDomain 以在对象的生命周期内使用。我想正确清理 AppDomain,所以我想我会在终结器中调用 Unload。不幸的是,这会导致抛出 CannotUnloadAppDomainException。AppDomain.Unload的 MSDN 文档说明:

在某些情况下,调用 Unload 会导致立即的 CannotUnloadAppDomainException,例如在终结器中调用它。

为什么是这样?成员变量“域”是否已清理?该清理是否会自动包括卸载 AppDomain,或者它是否仍会以某种无法访问的方式存在?有什么我应该做的,或者我可以安全地转储终结器吗?(我并不关心 GC 何时删除我的对象,只要它在此过程中被完全清理。)

0 投票
3 回答
22472 浏览

.net - 在我的析构函数中释放 Excel 对象

我正在使用 Microsoft.Interropt.Excel DLL 编写一个 Excel 类。我完成了所有功能,但我的析构函数中有错误。我想保存对我的文件的所有更改,并且我想释放所有源代码。我想把它们都放在我的析构函数中。但在我的析构函数中,Excel.ApplicationClass、Workbook 和 Worksheet 对象被一个异常填充,该异常具有消息“无法使用已与其底层 RCW 分离的 COM 对象”。所以我什么都不能保存,什么也不能关闭,因为我无法访问工作簿或工作表对象。

我不能访问 Destructor 中的类私有成员吗?