У меня возникли некоторые проблемы с использованием библиотеки поставщиков, где иногда объект, вычисленный библиотекой, был бы нулевым, когда он всегда должен иметь в нем действительные данные.
Функциональный код (после отладки проблемы с поставщиком) выглядит примерно следующим образом:
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
});
}
Процесс проверки является довольно трудоемкой операцией, поэтому я передаю ее задаче. Проблема у меня была в том, что изначально у меня не было вызова GC.SuppressFinalize(calibrationValidator), и когда приложение было запущено из сборки Release, то параметр validationResultsUsingRecomputedExtrinsics будет равен null. Если я запустил приложение из сборки Debug (с присоединенным или отсутствующим отладчиком), то validationResultsUsingRecomputedExtrinsics будет содержать достоверные данные.
Я не совсем понимаю, что сделал GC.SuppressFinalize() в этой ситуации или как она устранила проблему. Все, что я могу найти относительно GC.SuppressFinalize(), заключается в том, что он используется при реализации IDisposable. Я не могу использовать его в "стандартном" коде.
Как/почему добавление вызова в GC.SuppressFinalize(calibrationValidator) устраняет эту проблему?
Я понимаю, что без глубокого знания внутренних компонентов в библиотеке поставщиков это может быть невозможно узнать наверняка, но любое понимание поможет.
Приложение скомпилировано с VS2012, ориентированное на .NET 4.0. Для этой библиотеки поставщиков требуется, чтобы параметр useLegacyV2RuntimeActivationPolicy = "true" был указан в app.config.
Это оправдание, которое я получил от поставщика:
Команда SuppressFinalize гарантирует, что сборщик мусора не будет чистить что-то "ранним". Похоже, что по какой-то причине ваше приложение иногда получало сборщик мусора, немного усердный и очищающий объект, прежде чем вы действительно были с ним сделаны; это почти наверняка связано с возможностями и, возможно, из-за многопоточности, вызывающей путаницу в масштабе калибровочного валидатора. Ниже приведен ответ, который я получил от Engineering.
Поскольку переменная была создана в локальной области, и эта функция работает в фоновом потоке, коллекция Garbage Collection запускается в основном потоке, и кажется, что коллекция Garbage недостаточно умен в обработке многопоточных ситуаций. Иногда он просто высвобождает его слишком рано (внутреннее выполнение валидатора еще не закончено и по-прежнему нуждается в этой переменной).