简体   繁体   English

强制垃圾收集或反映到私人领域,这是不是很邪恶?

[英]Forced Garbage collection or reflection to a Private field, which is less evil?

We have a third party library that internally uses a SafeHandle to an unmanaged resource. 我们有一个第三方库,内部使用SafeHandle来处理非托管资源。 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. 但是,dispose实现中存在一个错误,阻止Handle在这些情况的子集中被关闭。 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 运行GC.Collect以使终结器运行并清理对象

  2. Use reflection to get at the Handle and close it if dispose fails to do so 如果处理失败,请使用反射来处理Handle并关闭它

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? 还有一些我们没有考虑过的方法比其中任何一种方法都不那么邪恶吗?

I'm in favour of private reflection. 我赞成私人反思。 It's a localized bug, so the solution should be local too. 这是一个本地化的bug,所以解决方案也应该是本地的。 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. 并且你可能会添加一些测试,一旦修复了bug就会注意到。 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. 另一方面,强制GC具有全局效应。 And there are many reasons(most of them bad) for interfering with the GC. 干扰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 Old New Thing:不要使用全局状态来管理本地问题

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);
}

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. Gc.Collect在整个应用程序中更像是一把锤子。 Where as your reflection code is brittle but should have a very small impact. 您的反射代码很脆弱,但影响非常小。

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. 至于反射与GC,我肯定会使用反射。 Like others have said, the GC may not work as expected. 像其他人所说的那样,GC可能无法按预期工作。 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. 我想注意:如果其他东西仍然引用了这个SafeHandle,并且你发布它,你可以很容易地将其他错误引入你的系统。

Taking the "CodeInChaos" argument forward why don't you call for collection on specific generation. 将“CodeInChaos”论证转发为什么不召集特定代的集合。

GC.GetGeneration(Object obj) will return the generation that object is in and GC.Collect(Int32 gen) . GC.GetGeneration(Object obj)将返回该对象所在的生成和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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM