强制垃圾收集或反射到私有字段,哪个更邪恶?

发布于 2024-11-08 12:37:40 字数 350 浏览 0 评论 0原文

我们有一个第三方库,它在内部使用 SafeHandle 来处理非托管资源。在某些错误情况下,有必要处置该对象并重新创建它。但是,处置实现中存在一个错误,该错误会阻止在这些情况的子集中关闭句柄。这会阻止新对象在其终结器运行之前成功创建。

在我们修复第三方代码之前,已经提出了两种解决方案(都是邪恶的)来解决这个问题:

  1. 运行 GC.Collect 来运行终结器并清理对象< /p>

  2. 使用反射获取 Handle,如果 dispose 失败则将其关闭

其中哪一个危害较小,为什么? 还有其他我们没有考虑过的比这两种方法更邪恶的方法吗?

We have a third party library that internally uses a SafeHandle to an unmanaged resource. In some error cases it is necessary to dispose of the object and recreate it. But, there is a bug in the dispose implementation that prevents the Handle from being closed in a subset of these cases. Which prevents new objects from being successfully created until its finalizer runs.

Two solutions (both evil) have been proposed to deal with this until we can get the third party code fixed:

  1. Run a GC.Collect to get the finalizer to run and clean up the object

  2. Use reflection to get at the Handle and close it if dispose fails to do so

which of these is less evil and why?
Is there some other method that we haven't considered that is less evil than either of these?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

日久见人心 2024-11-15 12:37:40

我赞成私人反思。这是一个本地化的错误,因此解决方案也应该是本地化的。而且您的代码的用途也更加清晰。您可能可以添加一些测试,以便在错误修复后注意到。因此,一旦不再需要,黑客就可以轻松删除。

...
thirdPartyObject.Dispose();
ThirdPartyDisposeBugWorkaround(thirdPartyObject);
...

void ThirdPartyDisposeBugWorkaround(ThirdPartyClass thirdPartyObject)
{
   //Do private reflection here
}

另一方面,强制 GC 会产生全局影响。干扰 GC 的原因有很多(其中大部分都是不好的)。您的代码的作用不太明显。因此,即使错误得到修复,调用也可能会保留。

旧的新事物:不要使用全局状态来管理本地问题

I'm in favour of private reflection. It's a localized bug, so the solution should be local too. And it's much clearer that what your code intends to do. And you probably can add some tests that notice once the bug has been fixed. So the hack can easily be removed once it's not needed anymore.

...
thirdPartyObject.Dispose();
ThirdPartyDisposeBugWorkaround(thirdPartyObject);
...

void ThirdPartyDisposeBugWorkaround(ThirdPartyClass thirdPartyObject)
{
   //Do private reflection here
}

Forcing a GC on the other hand has a global effect. And there are many reasons(most of them bad) for interfering with the GC. It's much less obvious what your code does. So the call might be kept even once the bug has been fixed.

Old New Thing: Don't use global state to manage a local problem

国粹 2024-11-15 12:37:40

我会进行反思,但要确保你有错误处理,明确出了什么问题,请记住,直到几年后,错误可能不会被触发,你的开发团队可能已经转变,没有人记得这个古怪的黑客。

try
{
   .. hacky reflection ..
}
catch(Exception ex)
{
    throw new Exception("Reflection on private field 'Xyz' of 3rd Party Component 'Abc' failed.  Was 'Abc' updated? Reflection is used due to bug in 'Dispose' implementation.", ex);
}

I would go with reflection, but make sure you have error handling around it that makes it explicitly clear what's wrong, keeping in mind the error might not get triggered until years from now and your dev team could have turned over and nobody remembers this wacky hack.

try
{
   .. hacky reflection ..
}
catch(Exception ex)
{
    throw new Exception("Reflection on private field 'Xyz' of 3rd Party Component 'Abc' failed.  Was 'Abc' updated? Reflection is used due to bug in 'Dispose' implementation.", ex);
}
一梦等七年七年为一梦 2024-11-15 12:37:40

首先选择有效的。如果它们都有效,请选择对系统影响最小的一个。 Gc.Collect 更像是贯穿整个应用程序的锤子。虽然您的反射代码很脆弱,但影响应该很小。

First pick the one that works. If they both work pick the one that has the least amount of impact on the system. Gc.Collect is more of a hammer across the whole application. Where as your reflection code is brittle but should have a very small impact.

街角迷惘 2024-11-15 12:37:40

如果它没有标记为密封,您可以继承它并实现您自己的处置。至于反射与GC,我肯定会使用反射。正如其他人所说,GC 可能无法按预期工作。它可以进行集合迭代,但实际上不会释放您的句柄。

我想指出的是:如果其他东西仍然引用了这个 SafeHandle,并且您释放了它,则可以轻松地将其他错误引入您的系统。

If it is not marked as sealed, you could inherit from it and implement your own dispose. As for the reflection vs GC, I would definately use reflection. Like others have said, the GC may not work as expected. It could do a collection iteration but not actually release your handle.

I would like to note: if something else still has a reference to this SafeHandle, and you release it, you could easily introduce other bugs into your system.

筱武穆 2024-11-15 12:37:40

继续讨论“CodeInChaos”的论点,为什么不呼吁对特定代进行收集呢?

GC.GetGeneration(Object obj) 将返回对象所在的代以及 GC.Collect(Int32 gen)

前任:

Int32 generation = GC.GetGeneration(theObject);
theObject = null;
GC.Collect(generation);
GC.WaitForPendingFinalizers();
GC.Collect(generation); // this is req because first collect puts thisObject on freachable queue not // garbaged yet.

Taking the "CodeInChaos" argument forward why don't you call for collection on specific generation.

GC.GetGeneration(Object obj) will return the generation that object is in and GC.Collect(Int32 gen).

Ex:

Int32 generation = GC.GetGeneration(theObject);
theObject = null;
GC.Collect(generation);
GC.WaitForPendingFinalizers();
GC.Collect(generation); // this is req because first collect puts thisObject on freachable queue not // garbaged yet.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文