堆栈回溯
启用单层存储器堆内存管理器
从单级存储堆函数生成 C2M1211 或 C2M1212 消息时,代码将检查名为 QGPL/QC2M1211 或 QGPL/QC2M1212的 *DTAARA。 如果数据区存在,那么将转储程序堆栈。 如果数据区不存在,那么不会执行任何转储。
启用太字节空间堆内存管理器
从太字节空间堆函数生成 C2M1211 消息或 C2M1212 消息时,代码将检查名为 QGPL/QC2M1211 或 QGPL/QC2M1212的 *DTAARA。 如果数据区存在并且包含至少 50 个字符的数据,那么将从数据区检索 50 个字符的字符串。 如果数据区中的字符串与下列其中一个字符串匹配,那么将触发特殊行为。
_C_TS_dump_stack
_C_TS_dump_stack_vfy_heap
_C_TS_dump_stack_vfy_heap_wabort
_C_TS_dump_stack_vry_heap_wsleep如果数据区不存在,那么不会执行转储或堆验证。
_C_TS_dump_stack 行为:- 数据区存在,但不包含字符数据。
- 数据区长度小于 50 个字符。
- 数据区不包含任何列出的字符串。
数据区中的字符串具有以下含义:
- _C_TS_dump_stack
将执行转储堆栈的缺省行为。 未执行堆验证。
- _C_TS_dump_stack_vfy_heap
转储堆栈后,将调用
_C_TS_malloc_debug()函数以验证堆控制结构。 如果在堆控制结构中检测到任何损坏,那么将转储堆错误和所有堆控制信息。 转储的任何堆信息都包含在与堆栈转储相同的文件中。 如果未检测到堆损坏,那么不会转储堆信息。执行验证后,控制将返回到生成 C2M1211 或 C2M1212 消息的原始程序,并继续执行。
- _C_TS_dump_stack_vfy_heap_wabort
_C_TS_dump_stack_vfy_heap_wabort具有与_C_TS_dump_stack_vfy_heap相同的验证行为。如果检测到堆损坏,那么将调用
abort()函数以停止执行,而不是将控制权返回给原始程序。- _C_TS_dump_stack_vfy_heap_wsleep
_C_TS_dump_stack_vfy_heap_wsleep具有与_C_TS_dump_stack_vfy_heap相同的验证行为。如果检测到堆损坏,那么将调用
sleep()函数以无限期休眠,并暂停执行以允许调试应用程序,而不是将控制权返回给原始程序。 需要手动结束应用程序。
_C_TS_malloc_debug 以验证堆的示例:CRTDTAARA DTAARA(QGPL/QC2M1212) TYPE(*CHAR) LEN(50)
VALUE('_C_TS_dump_stack_vfy_heap')分析
一旦数据区到位,就会创建名为 QPRINT 的假脱机文件,其中包含每个 C2M1211 消息或 C2M1212 消息的转储信息。 将为运行获取消息的作业的用户创建假脱机文件。 例如,如果获取 C2M1211 消息或 C2M1212 消息的作业是在用户标识 ABC123 下运行的服务器作业或批处理作业,那么将在用户标识 ABC123的输出队列中创建假脱机文件。 一旦获取了包含堆栈回溯的假脱机文件,就可以除去数据区,并分析回溯。
PROGRAM NAME PROGRAM LIB MODULE NAME MODULE LIB INST# PROCEDURE STATEMENT#
QC2UTIL1 QSYS QC2ALLOC QBUILDSS1 000000 dump_stack__Fv 0000001019
QC2UTIL1 QSYS QC2ALLOC QBUILDSS1 000000 free 0000001128
QYPPRT370 QSYS DLSCTODF37 QBUILDSS1 000000 __dl__FPv 0000000007
FSOSA ABCSYS OSAACTS FSTESTOSA 000000 FS_FinalizeDoc 0000000110
ABCKRNL ABCSYS A2PDFUTILS ABMOD_8 000000 PRT_EndDoc_Adb 0000000625
ABCKRNL ABCSYS A2PDFUTILS ABMOD_8 000000 PRT_EndDoc 0000000003
ABCKRNL ABCSYS A2ENGINE ABMOD_8 000000 ABCReport_Start 0000000087
ABCKRNL ABCSYS A2ENTRYPNT ABMOD_8 000000 ABCReport_Run 0000000056
ABCKRNL ABCSYS A2ENTRYPNT ABMOD_8 000000 ABCReport_Entry 0000000155
PRINTABC ABCSYS RUNBATCH ABMOD_6 000000 main 0000000040
PRINTABC ABCSYS RUNBATCH ABMOD_6 000000 _C_pep
QCMD QSYS 000422第一行是标题行,它显示程序名,程序库,模块名,模块库,指令号,过程名和语句号。
标题下的第一行始终是 dump_stack 过程-此过程正在生成 C2M1211 消息或 C2M1212 消息。 下一行是调用 dump_stack 过程的过程-几乎始终是 free 过程,但它可能是 realloc 或其他过程。 下一行是 __dl__FPv 过程,这是处理 C++ 删除运算符的过程。 对于 C++ 代码,此过程通常在堆栈中-对于 C 代码,它不是。
free 和 delete 函数是代表调用者释放内存的库函数。 它们对于确定内存问题的来源并不重要。
__dl__FPv 过程之后的行是使事情变得有趣的行。 在此示例中,过程称为 FS_FinalizeDoc ,此代码包含不正确的删除调用 (正在删除先前已删除/释放的对象)。 该应用程序的所有者需要在给定的语句号处查看该过程的源代码,以确定要删除/释放的内容。 在某些情况下,此对象是某种类型的本地对象,很容易确定问题。 在其他情况下,可以将对象作为参数传递到过程,并且需要检查该过程的调用者。 在这种情况下, PRT_EndDoc_Adb 过程是 FS_FinalizeDoc的调用者。
对于此示例,问题在 ABCSYS 库中的代码中。