Halcon FindNccModel 在 C# 中导致内存泄漏

Halcon FindNccModel causes memory leak in C#

在 C# 中使用 Halcon 13 函数 FindNccModel 会导致以下错误: HALCON 错误 #6001:运算符 find_ncc_model

中可用内存不足
class Program
{
    static void Main(string[] args)
    {
        HImage Image = new HImage(@"08_09_09_41_33_582_OK_000000153000.png");
        double MidpointRow = 1053.5210373923057, MidpointCol = 1223.5205413999142;

        int iCounter = 0;

        while (true)
        {
            HNCCModel model = new HNCCModel(@"000000135000Mark_0.ncm");

            HXLDCont hxCont = new HXLDCont();
            hxCont.GenRectangle2ContourXld(
                721.9213759213759,
                1775.862648221344,
                -0.99483767363676778,
                72,
                14.5);

            HTuple htRowXLD, htColXLD;
            hxCont.GetContourXld(out htRowXLD, out htColXLD);
            HTuple htRadius = new HTuple();
            htRadius = new HTuple(htRowXLD.TupleSub(MidpointRow).TuplePow(2) + htColXLD.TupleSub(MidpointCol).TuplePow(2)).TupleSqrt();
            HRegion hrAnnulus = new HRegion();
            hrAnnulus = hrAnnulus.GenAnnulus(MidpointRow, MidpointCol, htRadius.TupleMin() - 5.0, htRadius.TupleMax() + 5.0);

            HImage hiTemp = Image.Clone();
            HImage hiTemp2 = hiTemp.Rgb1ToGray();
            HImage hiTemp3 = hiTemp2.ReduceDomain(hrAnnulus);

            HTuple htRow, htColumn, Angle, Score;

            model.FindNccModel(hiTemp3, -0.39, 6.29, 0.65, 1, 0, "true", 0, out htRow, out htColumn, out Angle, out Score);

            hxCont.DisposeIfNotNull();
            hrAnnulus.DisposeIfNotNull();
            model.Dispose();

            hiTemp.DisposeIfNotNull();
            hiTemp2.DisposeIfNotNull();
            hiTemp3.DisposeIfNotNull();

            Console.WriteLine(iCounter++.ToString());
        }
    }
}

public static class DL_HalconUtilityClass
{
    public static HRegion GenAnnulus(this HRegion region, double dCenterRow, double dCenterColumn, double dRadiusSmall, double dRadiusBig)
    {
        region.GenEmptyRegion();

        if (dRadiusSmall > dRadiusBig)
        {
            throw new NotSupportedException("Wrong input parameters. Small radius is bigger than big radius.");
        }

        HRegion hrCircleSmall = new HRegion(dCenterRow, dCenterColumn, dRadiusSmall);
        HRegion hrCircleBig = new HRegion(dCenterRow, dCenterColumn, dRadiusBig);

        region = new HRegion();
        region = hrCircleBig.Difference(hrCircleSmall);

        hrCircleSmall.Dispose();
        hrCircleBig.Dispose();

        return region;
    }

    public static void DisposeIfNotNull(this HImage hiImage)
    {
        if (hiImage != null) hiImage.Dispose();
    }

    public static void DisposeIfNotNull(this HRegion hrRegion)
    {
        if (hrRegion != null) hrRegion.Dispose();
    }

    public static void DisposeIfNotNull(this HObject hoObject)
    {
        if (hoObject != null) hoObject.Dispose();
    }
}

函数本身可以运行在一个while循环中无限循环,但是如果它和我们的程序结合起来就会导致内存异常。另一方面,程序本身可以 运行 无休止地没有这个功能。同样有趣的是,错误发生在程序达到典型的 1.1 Gb 内存之前,这意味着存在内存泄漏。

我没有在 Halcon 文档中找到任何关于此问题的参考资料,升级到最新的 Halcon 13 版本或使用 Halcon XL 也没有帮助。有谁知道是什么导致了这个问题?

在您的代码中,您已经按照建议手动处置了大多数 HALCON 对象。您可能知道这是必要的,因为 .NET 垃圾收集器不知道托管对象可能使用的 HALCON 库处理的非托管内存量。

但是,您错过了处理包含 FindNccModel htRowhtColumnAngleScore.

结果的 HTuples

您可能还想将 HNCCModel 的创建移出 while 循环。

Halcon 有两个内存管理优化系统设置:global_mem_cache 和temporary_mem_cache。 global_mem_cache 没有影响,但将 temporary_mem_cache 参数设置为 "idle" 或 "shared" 解决了问题。

默认设置是"exclusive",其中每个线程都在本地缓存临时内存。这是 Halcon 文档的摘录:


'temporary_mem_cache' *), 'tsp_temporary_mem_cache' 该参数控制临时内存缓存的运行模式。临时内存缓存用于通过缓存在运算符执行期间临时使用的内存来加速应用程序。对于大多数应用程序,默认设置 ('exclusive') 将产生最佳结果。支持以下模式:

  • 'idle'临时内存缓存已关闭。此模式将使用最少的内存,但与其他模式相比也会降低性能。

  • 'shared' 所有临时内存都全局缓存在临时内存库中。此模式将使用比 'exclusive' 模式更少的内存,但通常也会提供较低的性能。

  • 'exclusive' 每个线程的所有临时内存都缓存在本地。此模式将使用最多内存,但通常也会提供最佳性能。

  • 'aggregate' 大于'alloctmp_max_blocksize'参数设置的阈值的临时内存块缓存在全局内存库中,而所有较小的块都聚合成一个为每个线程在本地缓存的块。如果禁用全局内存库,则会释放大块。聚合块的大小将根据线程到目前为止看到的临时内存使用情况进行调整,但不会大于 'alloctmp_max_blocksize'(如果设置)或小于 'alloctmp_min_blocksize'(如果设置)。此模式平衡内存使用和速度,但需要为应用程序的内存使用模式正确设置 'alloctmp_min_blocksize' 和 'alloctmp_max_blocksize' 以确保有效性。

注意缓存模式'idle'设置为独占运行模式,而其他模式设置为可重入模式

为了向后兼容,值 'false' 和 'true' 也被接受;它们分别对应'idle'和'exclusive'。