Dav*_*Nay 9 .net c# garbage-collection
我一直在使用供应商库时遇到一些问题,当库中计算的实体应该总是在其中有效数据时,该实体偶尔会为空.
功能代码(在调试供应商问题后)大致如下:
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, crspFeatures, getRaw2DFromPhys3Ds, out validationResultUsingOriginalCalibrations, out validationResultsUsingRecomputedExtrinsics);
Calibration.CalibrationValidations.Add(new CalibrationValidation
{
Timestamp = DateTime.Now,
UserName = Globals.InspectionSystemObject.CurrentUserName,
ValidationResultUsingOriginalCalibrations = validationResultUsingOriginalCalibrations,
ValidationResultsUsingRecomputedExtrinsics = validationResultsUsingRecomputedExtrinsics
});
}
Run Code Online (Sandbox Code Playgroud)
验证过程是一个相当耗时的操作,所以我将其交给任务.我遇到的问题是,最初我没有调用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"选项.
这是我从供应商那里得到的理由:
SuppressFinalize命令确保垃圾收集器不会"提前"清理某些内容.似乎由于某种原因,你的应用程序有时让垃圾收集器有点热心并在你真正完成之前清理对象; 它几乎肯定与范围相关,并且可能是由于多线程导致校准的雾化器范围的混淆.以下是我从Engineering获得的回复.
因为变量是在本地范围内创建的,并且该函数在后台线程中运行,所以垃圾收集在主线程中运行,并且似乎垃圾收集在处理多线程情况时不够智能.有时,它只是过早发布它(验证器的内部执行尚未完成,仍然需要此变量).
Han*_*ant 16
这很可能是解决过早垃圾收集问题的黑客行为.非托管代码并不罕见,在相机应用程序中很常见.这不是一个健康的黑客,很可能这会导致资源泄漏,因为终结器不会执行.非托管代码的包装器几乎总是在终结器中有所作为,他们需要释放非托管内存是很常见的.
问题在于,在非托管代码运行时,可以对calibrationValidator对象进行垃圾回收.在程序中有另一个线程可能会导致这种情况,因为其他线程可以分配对象并触发GC.在测试时,代码的所有者很容易错过这一点,或者在使用多个线程时从未测试过它,或者只是没有足够幸运地在错误的时间触发GC.
正确的解决方法是确保抖动在通过调用之后标记正在使用的对象,以便垃圾收集器不会收集它.您可以GC.KeepAlive(calibrationValidator)在Execute()通话后添加.