调试内存管理器

调试内存管理器主要用于查找应用程序不正确的堆使用情况。 它未针对性能进行优化,可能会对应用程序的性能产生负面影响。 但是,它对于确定不正确的堆使用率很有用。

内存管理错误有时是由于写入超过分配的缓冲区的末尾而导致的。 直到被覆盖的内存 (通常属于另一个分配) 被引用并且不再包含期望的数据之后,才会出现症状。

调试内存管理器允许检测内存覆盖,内存过度读取,重复释放以及已释放内存的复用。 调试内存管理器检测到的内存问题会导致以下两种行为之一:

  • 如果在发生不正确使用时检测到问题,那么将生成 MCH 异常消息 (通常为 MCH0601, MCH3402或 MCH6801)。 在这种情况下,错误消息通常会停止应用程序。
  • 如果直到稍后才检测到该问题,那么在发生不正确的使用后,将生成 C2M1212 消息。 在这种情况下,消息通常不会停止应用程序。
调试内存管理器通过两种方式检测内存覆盖和内存过度读取:
  • 首先,它使用受限访问内存页面。 在每次分配之前和之后放置具有受限访问权的内存页面。 每个内存块在 16 字节边界上对齐,并尽可能靠近页面末尾。 由于仅在页边界上允许内存保护,因此此对齐允许对内存覆盖和内存过度读取进行最佳检测。 从其中一个受限访问内存页面进行的任何读或写操作都会立即导致 MCH 异常。
  • 其次,它在每次分配之前和之后使用填充字节。 在分配时将每个分配前的几个字节初始化为预设字节模式。 将分配大小舍入为 16 个字节的倍数所需的分配后的任何填充字节在分配时初始化为预设字节模式。 当释放分配时,将验证所有填充字节以确保它们仍包含期望的预设字节模式。 如果已修改任何填充字节,那么调试内存管理器将生成 C2M1212 消息,原因码为 X'80000000 ' ,指示此事实。

分配

每个分配请求都需要大量额外内存。 额外内存的原因如下:

  • 分配前的内存页面 (仅限单级别商店版本)
  • 分配后的内存页面
  • 每个分配上的头
  • 16 字节边界上每个内存块的对齐
每次分配的头大小为 16 个字节。 每个块必须在 16 字节边界上对齐。 单层存储器版本中大小为 n 的分配所需的内存总量为:
size = ROUND((PAGESIZE * 2) + n + 16, PAGESIZE)

例如,页面大小为 4096 字节的大小 37 的分配需要大小为 ROUND (8192 + 37 + 16 , 4096) ,即等于 12,288 字节。

太字节空间版本中大小为 n 的分配所需的内存总量为:

size = ROUND(PAGESIZE + n + 16, PAGESIZE)

例如,页面大小为 4096 字节的大小 37 的分配要求大小为 ROUND (4096 + 37 + 16 , 4096) ,等于 8,192 字节。

释放

使用 free 操作释放的内存块将返回到系统。 设置了页面保护属性,以便对该内存块的任何进一步读或写访问都会生成 MCH 异常。

重新分配

在所有情况下,都会执行以下处理:
  • 将分配所请求大小的新块。
  • 数据将从原始块移至新块。
  • 原始块随 free 操作一起返回。
  • 新块将返回给调用者。

启用调试内存管理器

缺省情况下不启用调试内存管理器,而是通过设置以下环境变量来启用和配置:
QIBM_MALLOC_TYPE=DEBUG
QIBM_MALLOC_DEBUG_OPTIONS=options

要使用缺省设置启用调试内存管理器,需要指定 QIBM_MALLOC_TYPE=DEBUG。 要使用用户指定的配置选项来启用调试内存管理器,请设置 QIBM_MALLOC_DEBUG_OPTIONS=options ,其中 options 是一个或多个配置选项的空白定界列表。

如果指定了 QIBM_MALLOC_TYPE=DEBUG 环境变量,并且调用了 _C_Quickpool_Init() 函数,则环境变量设置优先于 _C_Quickpool_Init() 函数,并且 _C_Quickpool_Init() function 返回 -1 值,表示已启用备用堆管理器。

配置选项

以下配置选项可用:

MALLOC_INIT: N

此选项可用于指定将已分配内存的每个字节初始化为给定值。 值 N 表示 0 到 255 范围内的整数。

缺省情况下未启用此选项。

FREE_INIT: N

此选项可用于指定将释放内存的每个字节初始化为给定值。 值 N 表示 0 到 255 范围内的整数。

缺省情况下未启用此选项。

可以指定任意数量的选项,并且可以按任意顺序指定这些选项。 空格是用于分隔配置选项的唯一有效定界符。 每个配置选项只应指定一次。 如果多次指定了配置选项,那么仅应用最终实例。 如果使用无效值指定了配置选项,那么将忽略该配置选项。

示例

ADDENVVAR ENVVAR(QIBM_MALLOC_DEBUG_OPTIONS) LEVEL(*JOB) REPLACE(*YES) VALUE('')

ADDENVVAR ENVVAR(QIBM_MALLOC_DEBUG_OPTIONS) LEVEL(*JOB) REPLACE(*YES) 
VALUE('MALLOC_INIT:255 FREE_INIT:0')

第一个示例表示缺省配置值。 第二个示例说明了正在指定的所有选项。

相关函数

没有可用于启用或指定调试内存管理器的配置选项的功能。 使用环境变量支持来启用或指定配置选项。

注:
  1. 使用调试内存管理器同时调试单个应用程序或一小组应用程序。

    调试内存管理器不适用于全时,常量或系统范围的使用。 虽然它设计为对正在调试的应用程序的性能影响最小,但如果在系统范围内使用它,可能会对整体系统吞吐量产生严重的负面影响。 这可能会导致严重的系统问题,例如过度使用系统辅助存储池 (ASP)。

  2. 与缺省内存管理器相比,调试内存管理器耗用的内存要多得多。 因此,调试内存管理器可能不适合在某些调试情况下使用。

    由于每个分配需要两个内存页面或更多额外内存,因此发出许多小型分配请求的应用程序会看到其内存使用率显着增加。 这些程序可能会迂到新的故障,因为内存分配请求由于内存不足而被拒绝。 这些故障不一定是正在调试的应用程序中的错误,也不是调试内存管理器中的错误。

    对于已分配的最大堆存储量,单级别存储版本限制为略小于 4 GB。 调试内存管理器每次分配至少分配 3 个页面,这允许少于 350,000 个未完成的堆分配 (页面大小为 4096 字节)。

  3. 调试内存管理器的单级存储版本在单独的 16 MB 段中执行每次分配,这可能导致系统更快地使用临时地址。

相关信息