C# · 12月 31, 2021

c# – 这个使用GC.SuppressFinalize()感觉不对

在使用供应商库时,我一直在使用一些问题,当库中计算的实体偶尔在其中总是具有有效的数据时,该库就会为空.

功能代码(在与供应商调试问题之后)大致如下:

Task.Factory.StartNew(() => ValidateCalibration(pelRectRaw2Ds,crspFeatures,Calibration.Raw2DFromPhys3Ds)); ….. private void ValidateCalibration(List<Rectangle> pelRectRaw2Ds,List<List<3DCrspFeaturesCollection>> crspFeatures,List<3DCameraCalibration> getRaw2DFromPhys3Ds) { var calibrationValidator = new 3DCameraCalibrationValidator(); // This is required according to vendor otherwise validationResultsUsingRecomputedExtrinsics is occasionally null after preforming the validation GC.SuppressFinalize(calibrationValidator); 3DCameraCalibrationValidationResult validationResultUsingOriginalCalibrations; 3DCameraCalibrationValidationResult validationResultsUsingRecomputedExtrinsics; calibrationValidator.Execute(pelRectRaw2Ds,getRaw2DFromPhys3Ds,out validationResultUsingOriginalCalibrations,out validationResultsUsingRecomputedExtrinsics); Calibration.CalibrationValidations.Add(new CalibrationValidation { Timestamp = DateTime.Now,UserName = Globals.inspectionSystemObject.CurrentUserName,ValidationResultUsingOriginalCalibrations = validationResultUsingOriginalCalibrations,ValidationResultsUsingRecomputedExtrinsics = validationResultsUsingRecomputedExtrinsics }); }

验证过程是一个相当耗时的操作,所以我把它交给一个任务.我曾经遇到过的问题是,原来我没有调用GC.SuppressFinalize(calibrationValidator),而当应用程序从Release版本运行时,out参数validationResultsUsingRecomputedExtrinsics将为null.如果我从Debug构建运行应用程序(有或没有调试器附加),那么validationResultsUsingRecomputedExtrinsics将包含有效的数据.

我不完全明白GC.SuppressFinalize()在这种情况下所做的事情,或者如何解决问题.我可以找到关于GC.SuppressFinalize()的一切,就是在实现IDisposable时使用它.我在“标准”代码中找不到任何用途.

如何/为什么添加对GC.SuppressFinalize(calibrationValidator)的调用解决了这个问题?

我明白,如果没有对供应商图书馆的内部部分的深入了解,可能无法确定,但任何见解都将有所帮助.

该应用程序使用针对.NET 4.0的VS2012进行编译.该供应商库要求在app.config中指定useLegacyV2RuntimeActivationPolicy =“true”选项.

这是我从供应商那里得到的理由:

The SuppressFinalize command makes sure that the garbage collector will not clean something up “early”. It seems like for some reason your application was sometimes having the garbage collector get a bit zealous and clean up the object before you were truly done with it; it is almost certainly scope related and possibly due to the multi-threading causing confusion on the scope of the calibrationValidator. Below is the response I got from Engineering.

Because the variable was created in the local scope,and that function runs in the background thread,Garbage Collection runs in the main thread,and it seems that the Garbage collection is not smart enough in handling multi-thread situations. Sometimes,it just releases it too early (internal execution of validator not finished yet,and still needs this variable).

解决方法 这很可能是一个黑客来解决早期的垃圾收集问题.不常见的非托管代码,典型的相机应用程序.这不是一个健康的黑客,很可能会导致资源泄漏,因为终结器不执行.非托管代码的包装器在终结器中几乎总是有事情需要释放非托管内存是非常常见的.

有问题的是,在非托管代码运行时,可以对calibrationValidator对象进行垃圾回收.在你的程序中有另一个线程使得这可能是因为其他线程可以分配对象并触发GC.在测试期间,这是非常容易错过的代码的所有者,无论是从未测试过,而使用多线程,或者没有足够幸运地在错误的时间触发GC.

您最后的正确的修复是确保抖动标记正在使用的对象通过呼叫,以便垃圾回收器不会收集它.您可以在执行Execute()调用后添加GC.KeepAlive(calibrationValidator).