【发布时间】:2010-10-22 08:25:18
【问题描述】:
大多数时候我的 GLib 程序运行良好。然而,当日志喜欢
**(进程:pid):消息(递归):blah lah blah
出现,程序将中止。
GLib 手册说 G_LOG_FLAG_RECURSION 默认被认为是致命的。
但我就是不明白“递归消息”是什么意思?什么时候会出现递归消息?
谢谢
【问题讨论】:
大多数时候我的 GLib 程序运行良好。然而,当日志喜欢
**(进程:pid):消息(递归):blah lah blah
出现,程序将中止。
GLib 手册说 G_LOG_FLAG_RECURSION 默认被认为是致命的。
但我就是不明白“递归消息”是什么意思?什么时候会出现递归消息?
谢谢
【问题讨论】:
浏览 glib/gmessages.c 给我的印象非常深刻,如果 g_logv() 需要自己记录错误,则设置了 G_LOG_FLAG_RECURSION。
考虑内存不足;当内存分配尝试失败时,程序将尝试记录内存分配失败,并可能退出。当日志记录例程尝试分配内存来记录消息时,它可能会失败。因此,日志记录例程会跟踪它们被调用的“深度”,并切换内存分配策略(它们在堆栈上而不是在堆上分配),如果它是递归日志记录调用。
每当日志记录例程收到错误消息并想要记录错误时,确实会发生一些不好的事情,因此尝试使用另一种机制进行日志记录然后退出是有意义的。 p>
因此,您可能只是看到了真正问题的遥远征兆。您可以使用ltrace(1) 来尝试发现问题,或者您可以启用核心转储 (ulimit -c unlimited) 并尝试使用 gdb 的 bt 命令查找导致程序崩溃的调用链。
【讨论】:
请注意,如果您正在注册自定义处理程序(使用g_log_set_handler)并且该处理程序(或其被调用者之一)尝试通过调用g_* 例程。
还要注意,glib 决定任何递归也应该是致命的(即使不是无限的只有一层深度)。这对于 sarnold 对内部故障递归的回答中描述的情况当然是有意义的,但在自定义处理程序重复出现的情况下尝试解决问题时可能并不明显。因此,glib 早在第一次递归调用 g_* 时就检测到递归;它甚至没有检查您的自定义处理程序是否已附加。因此,您将永远不会看到对处理程序的递归调用。所有这些都意味着在处理程序的主体(和类似的事情)中小心地取消注册处理程序等努力是徒劳的。
您必须绝对确保自定义处理程序的调用堆栈中的任何内容都不会调用 g_* 例程(如果您处理对外部代码的调用并且确实使尝试将日志消息传递到一个遥远的目的地或什么的)。
【讨论】: