这种利用GC.Sup pressFinalize()感觉不对 [英] This use of GC.SuppressFinalize() doesn't feel right

查看:149
本文介绍了这种利用GC.Sup pressFinalize()感觉不对的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直有一些问题,利用供应商库,其中偶尔库计算的实体将成为空时,它应该始终有有效的数据在里面。

该功能code(调试问题与供应商之后)大致如下:

  Task.Factory.StartNew(()=> ValidateCalibration(pelRectRaw2Ds,crspFeatures,Calibration.Raw2DFromPhys3Ds));

    .....

    私人无效ValidateCalibration(名单<矩形> pelRectRaw2Ds,名单,其中,名单,其中,3DCrspFeaturesCollection>> crspFeatures,名单,其中,3DCameraCalibration> getRaw2DFromPhys3Ds)
    {
        VAR calibrationValidator =新3DCameraCalibrationValidator();

        //这是根据厂商的要求,否则validationResultsUsingRecomputedExtrinsics是preforming验证后,偶尔空
        GC.Sup pressFinalize(calibrationValidator);

        3DCameraCalibrationValidationResult validationResultUsingOriginalCalibrations;
        3DCameraCalibrationValidationResult validationResultsUsingRecomputedExtrinsics;
        calibrationValidator.Execute(pelRectRaw2Ds,crspFeatures,getRaw2DFromPhys3Ds,出validationResultUsingOriginalCalibrations,出validationResultsUsingRecomputedExtrinsics);

        Calibration.CalibrationValidations.Add(新CalibrationValidation
            {
                时间戳= DateTime.Now,
                USERNAME = Globals.InspectionSystemObject.CurrentUserName,
                ValidationResultUsingOriginalCalibrations = validationResultUsingOriginalCalibrations,
                ValidationResultsUsingRecomputedExtrinsics = validationResultsUsingRecomputedExtrinsics
            });
    }
 

确认过程是一个相当耗时的操作,所以我把它开了一个任务。我的问题是,我原本没有调用GC.Sup pressFinalize(calibrationValidator),当应用程序从一个发布版本中运行,则输出参数validationResultsUsingRecomputedExtrinsics将是空的。如果我跑的应用程序从调试版本(带或不带附加调试器),然后validationResultsUsingRecomputedExtrinsics将包含有效数据。

我不完全理解GC.Sup pressFinalize()在这种情况下所做的一切,或者它是如何解决了问题。所有我能找到有关GC.Sup pressFinalize()是实现IDisposable接口的时候才用。我找不到标准code任何使用它。

如何/为什么加入呼叫GC.Sup pressFinalize(calibrationValidator)的解决这个问题?

据我所知,没有供应商库的内部情况了如指掌,它可能无法就知道肯定,但任何有识之士将有所帮助。

应用程序被编译VS2012,针对.NET 4.0。该供应商库需要在app.config中指定了useLegacyV2RuntimeActivati​​onPolicy =真的选项。

这是我从供应商处收到的理由:

  

在燮pressFinalize命令可以确保垃圾收集器将不干净的东西了早。这似乎是出于某种原因,你的应用程序有时有垃圾收集得到位热心和清理对象之前,你是真正用它做;它几乎肯定范围有关,可能是由于多线程发生卷calibrationValidator的范围混乱。下面是我从工程得到了响应。

     

由于变量是在本地范围内创建,并在后台线程函数运行,在主线程垃圾收集运行,似乎垃圾收集是不是在处理多线程的情况下足够聪明。有时,它只是释放太早了(还没有完成验证程序的内部执行,并且仍然需要这个变量)。

解决方案

这是在所有的可能性一劈,解决了premature垃圾收集问题。并不鲜见与非托管code,典型的摄像头应用程序。这是不是一个健康的黑客攻击,很好的赔率,这将导致资源流失,因为终结器不会执行。包装的非托管code几乎总是有事情做的终结,这是很常见的,他们需要释放非托管内存。

目前的问题是,calibrationValidator对象可以是垃圾非托管code运行时收集。有你的程序中另一个线程使这种可能,因为其他的线程可以分配对象,并触发GC。这是很容易通过的code业主,而使用多线程或者只是没有得到足够幸运,触发GC在错误的时间错过,同时测试,无论是从未测试过。

这是您的最终正确的解决方法是,以确保抖动标志着过去使用呼叫的对象,这样的垃圾收集器将不会收集。您可以通过添加 GC.KeepAlive(这样做calibrationValidator) 中的执行()通话后。

I have been having some issues with utilizing a vendor library where occasionally an entity calculated by the library would be null when it should always have valid data in it.

The functioning code (after debugging the issue with the vendor) is roughly as follows:

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

The validation process is a fairly time consuming operation so I hand it off to a Task. The problem I had was that originally I did not have the call to GC.SuppressFinalize(calibrationValidator) and when the application was run from a Release build, then the out parameter validationResultsUsingRecomputedExtrinsics would be null. If I ran the application from a Debug build (either with or without the Debugger attached) then validationResultsUsingRecomputedExtrinsics would contain valid data.

I don't fully understand what GC.SuppressFinalize() has done in this situation, or how it has fixed the problem. Everything I can find regarding GC.SuppressFinalize() is that it is used when implementing IDisposable. I can't find any use of it in "standard" code.

How/why does the addition of the call to GC.SuppressFinalize(calibrationValidator) fix this problem?

I understand that without intimate knowledge of the internals of the vendor library, it might not be possible to know for sure, but any insight would help.

The application is compiled with VS2012, targeting .NET 4.0. That vendor library requires that the useLegacyV2RuntimeActivationPolicy="true" option is specified in app.config.

This is the justification I received from the vendor:

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).

解决方案

This is in all likelihood a hack to solve a premature garbage collection problem. Not uncommon with unmanaged code, typical in camera applications. It is not a healthy hack, good odds that this will cause a resource leak because the finalizer doesn't execute. Wrappers for unmanaged code almost always have something to do in the finalizer, it is very common that they need to release unmanaged memory.

At issue is that the calibrationValidator object can be garbage collected while the unmanaged code is running. Having another thread in your program makes this likely since that other thread can be allocating objects and trigger a GC. This is very easy to miss by the owner of the code while testing, either by never having tested it while using multiple threads or just not getting lucky enough to trigger a GC at the wrong time.

The proper fix on your end is to ensure that the jitter marks the object in use past the call so that the garbage collector won't collect it. You do so by adding GC.KeepAlive(calibrationValidator) after the Execute() call.

这篇关于这种利用GC.Sup pressFinalize()感觉不对的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆