HALCON: 内存管理(Memory Management)

内存管理(Memory Management)

.net框架的运行时环境CLR(公共语言运行时)有一种被称为垃圾收集器的机制,CLR使用它来从内存中移除不再需要的.net对象。

正如前面提到的,在导出的c#代码中,每个标志性的对象都由一个.net HObject对象表示。从垃圾收集器的角度来看,.net HObject对象相当小。因此,它可能不会从内存中收集,尽管底层的iconic对象(例如图像)实际上可能会占用很大一部分内存。为了避免这种影响导致的内存泄漏,在导出的代码中,每个iconic对象在被赋值之前都会被显式地清除(disposed)

HALCON的所有类,不仅是HImageHRegionHTupleHFramegrabber等,还有在过程方法中调用操作符时使用的类HObject,都会在析构函数中自动释放已分配的资源(参见“析构函数和HALCON操作符”一节)。此外,当重新构造实例时,例如,通过“构造函数和Halcon操作符”一节中提到的一个已经初始化的实例调用CreateBarCodeModel,已经分配的内存在重用实例之前自动释放。因此,在HALCON/c++中不需要调用操作符ClearObj; 更重要的是,如果您使用它,HALCON将会抱怨已经释放的内存。要在实例超出范围之前显式地释放资源,可以调用实例的Clear()方法。

HALCON提供了复杂的内存管理,不仅可以处理iconic对象,还可以分配/释放任意数据。请专门使用相应的HALCON扩展包接口例程。不要使用操作系统的标准例程(mallocfree)在堆上创建/销毁内存块,因为HALCON例程提供了缓存机制、临时数据的垃圾收集和调试工具。

我们强烈建议不要在HALCON操作符中使用全局变量。如果它们不可避免,至少使它们在使用文件中是静态的。如果这是不可取的,将它们分组到结构中,以保持全局名称的数量较小。

如果使用静态变量,请注意它们是在多个线程之间共享的。请注意,HALCON使用多线程来利用多处理器或多核硬件。这意味着,您的代码的多个实例实际上将共享所有静态变量!!!此外,要注意大型静态数组会消耗大量内存—请记住,HALCON是一个包含数百个操作符的非常大的系统。

永久数据(Permanent Data)

HALCON扩展包接口还提供了永久分配/释放内存的例程(参见图3.4和图3.5)。它们的工作方式类似于标准的C过程mallocfree,但对小数据块使用缓存机制,并提供额外的调试信息。

Names

    HAlloc, HRealloc, HFree, HNewImage, HNewImagePtr, HAllocXLDCont, HFreeXLDCont

Synopsis

    #include "Halcon.h"

    Herror HAlloc( Hproc_handle proc_handle, size_t       size, void         **pointer)

    Herror HRealloc(Hproc_handle proc_handle, void         *pointer

                   size_t       size, void         **new_pointer)

    Herror HFree( Hproc_handle  proc_handle, void          *pointer)

    Herror HNewImage(Hproc_handle  proc_handle, Himage        *image,

                      HINT          kind, HIMGDIM       width, HIMGDIM       height)

    Herror HNewImagePtr( Hproc_handle  proc_handle,

                          Himage        *image, HINT          kind,

                          HIMGDIM       width, HIMGDIM       height,

                          void          *data, HBOOL         initImg)

    Herror HAllocXLDCont( Hproc_handle  proc_handle, Hcont **cont, HITEMCNT num_points)

    Herror HFreeXLDCont( Hproc_handle  proc_handle, Hcont         *cont)

Figure 3.4: General memory management within HALCON.

注意,与HAllocLocal相比,HAlloc分配的内存在HALCON操作符执行后不会自动释放。因此,应该使用这个例程来分配永久数据。

例如,存储在HALCON iconic对象数据库中的所有iconic对象都用这个例程分配(参见“处理标志性对象和控制参数”和“典型供应程序的特殊例程”一章)

For example, all the iconic objects stored in the HALCON database of iconic objects are allocated with this routine (see chapter “Handling Iconic Objects and Control Parameters” and chapter “Special Routines for Typical Supply Procedures”).

HNewImage在数据结构Himage(参见“像素数据(Himage))中基于HAlloc分配原始图像数据。此外,将初始化image并将时间戳设置为当前时间。如果使用HALCON操作符set_system'init_new_image'设置为'true',则图像矩阵本身初始化为0。该标志可以在HALCON内部使用扩展包接口调用HReadGV读取。

HReadGV (proc_handle HGInitNewImage &init_new_img);

with init_new_img of type HBOOL and set

HWriteGV (proc_handle HGInitNewImage,{,});

因此,可以缓冲该标志的全局设置,在HNewImage之前将该标志设置为FALSE,然后在之后恢复旧的值,如果你想在任何情况下防止初始化。

HNewImagePtr不为图像数据分配内存,而是将指针数据插入到Himage结构图像中。对于这个例程,图像数据的初始化是通过参数initImg控制的。注意,如果你在底层的Himage结构中插入了一个没有通过HAlloc分配的内存块(参见“创建对象和写入输出对象参数”一节中的HPutImage),你会在释放图像对象时遇到程序崩溃。

对于HNewImageHNewImagePtrimage中原始数据的像素类型由参数kind指定。支持的值请参见图4.2

HAllocXLDCont分配一个Hcont类型的XLD轮廓(参见“XLD (Hcont, Hpoly)”一节),包括num_points轮廓点的内存。在内部,这个例程是基于HAlloc的。HFreeXLDCont用于再次释放轮廓线(包括所有为cont定义的点和所有属性,参见此页)

Names

    HAllocRL, HAllocRLNum, HReallocRLNum, HFreeRL

Synopsis

    #include "Halcon.h"

    Herror HAllocRL(Hproc_handle proc_handle, Hrlregion    **region)

    Herror HAllocRLNum(Hproc_handle proc_handle, Hrlregion    **region, size_t       len)

    Herror HReallocRLNum( Hproc_handle proc_handle, Hrlregion    *region, size_t       len,

                          Hrlregion    **new_region)

    Herror HFreeRL(       Hproc_handle proc_handle, Hrlregion    *region)

Figure 3.5: General memory management for region data.

使用方便的例程HAllocRLHAllocRLNumHReallocRLNumHFreeRL(见图3.5)来处理基于HAlloc的永久区域数据。否则,它们的行为类似于HAllocRLTmp等。例如,使用HIncrRL(章节“HIncrRL)HAllocRL分配更多的内存,参见此页。注意,使用HReallocRLNum可以改变区域的大小(例如,和弦的数量)

调试(Debugging)

HALCON内存管理提供了调试机制。这个调试是通过set_check('memory')打开的,可以通过set_check('~memory')关闭。每次释放内存块时,都会自动执行一些一致性检查。此外,可以在任何时候使用特定的Extension Package Interface例程检查内存块的一致性以查找调试原因,见图3.6

Names

    HTestMem, HTestPtr, HTestAllTmp, HTestTmp

Synopsis

    #include "Halcon.h"

    Herror HTestMem(void)

    Herror HTestPtr(void          *pointer)

    Herror HTestAllTmp(Hproc_handle  proc_handle)

    Herror HTestTmp(Hproc_handle  proc_handle, void *pointer)

Figure 3.6: HALCON memory management: Check of consistency.

HTestMem检查所有分配给HAllocHAllocLocal的内存,而HTestPtr只检查指定的内存块,这些内存块必须分配给HAlloc。与此类似,HTestAllTmp检查所有通过HAllocTmp分配的内存,HTestTmp检查指定的块。如果一致性检查失败,例程将返回错误代码(H_ERR_ICM—内存不一致)。此外,如果全局变量HDoLowError设置为TRUE,它们会在stderr(unix系统)或警告框(Windows)中显示错误的描述。这个变量可以在应用程序中使用set_system操作符("do_low_error""true"/"false")来设置,也可以直接在新编写的操作符中使用。

构造函数(Constructors)和Halcon操作符

HObject        image;

HTuple         barcode;

HObject        code_region;

HTuple         result;

ReadImage(&image, "barcode/ean13/ean1301");

CreateBarCodeModel(HTuple(), HTuple(), &barcode);

FindBarCode(image, &code_region, barcode, "EAN-13", &result);

Figure 5.4: Using FindBarCode via HBarCode, via HImage, or in the procedural approach.

如图5.4所示,HALCON/c++参数类提供了额外的构造函数,这些构造函数基于合适的HALCON操作符。示例中使用的HImageHBarCode构造函数分别基于ReadImageCreateBarCodeModel

经验之谈:如果类在操作符中只作为输出参数出现,则会自动存在基于该操作符的构造函数。因此,可以基于CreateBarCodeModel构造HBarCode实例,如图5.4所示,基于CreateShapeModel构造HShapeModel实例,基于OpenFramegrabber构造HFramegrabber实例等等。注意,对于存在许多这样的操作符的类(例如HImage),只有一个具有明确形参列表的常用操作符子集实际用作构造函数。

此外,所有类都有空的构造函数来创建未初始化的对象。例如,你可以用默认构造函数创建一个HBarCode实例,然后使用CreateBarCodeModel初始化它,如下所示:

HBarCode       barcode;

barcode.CreateBarCodeModel(HTuple(), HTuple());

如果实例已经初始化,相应的数据结构将在重新构造和初始化它们之前自动销毁(参见“析构函数和Halcon操作符”一节)。句柄类在“其他句柄类”一节中有更详细的描述。

HImage image;                  // still uninitialized

image.ReadImage("clip");

下面我们简要介绍一下最重要的类。可以在HALCON操作符引用中找到可用构造函数的完整和最新列表,%HALCONROOT%\ \中对应的头文件包括\cpp

  1. Images: The class HImage provides constructors based on the operators ReadImage, GenImage1, and GenImageConst.
  2. Regions: The class HRegion provides constructors based on operators like GenRectangle2 or GenCircle.
  3. Windows: The class HWindow provides a constructor based on the operator OpenWindow.

当然,您可以使用CloseWindow关闭窗口,然后使用OpenWindow再次打开它。与iconic的参数类相比,你可以通过HWindow的实例以直观的方式调用“类构造函数”操作符OpenWindow,即修改调用实例;此外,还返回相应的句柄。HWindow在“Windows”一节中有更详细的描述。

析构函数(Destructors)和Halcon操作符

所有的HALCON/c++类都提供了默认析构函数,它会自动释放相应的内存。

封装句柄的类的默认析构函数,例如HShapeModelHFramegrabber,工作原理与ClearShapeModelCloseFramegrabber类似。不需要调用这些操作符,因为你可以像“构造函数和Halcon操作符”一节中描述的那样重新初始化实例。

基本上,我们要区分销毁句柄和销毁底层数据结构。数据结构可以通过两种方式销毁:

  1. 在删除对数据结构的最后一个引用时自动销毁。
  2. 通过调用操作符显式地调用,例如CloseWindow。显式销毁会使引用失效,但访问是安全的。

HObjectHRegionHImageHXLDHXLDContHXLDPolyHXLDModParaHXLDParaHXLDExtPara、操作符不能作为类成员使用,但将在释放对象实例的资源时自动调用。这发生在垃圾收集的结束阶段,或在显式调用Dispose()方法时。

向量的析构(Destruction of Vectors)

如果HObjectVectorHTupleVector在以后的处理中不再需要它的内容,那么应该使用.dispose()清除它。

vectorObj.Dispose ();

你可能感兴趣的:(HALCON,halcon)