为什么GLib在递归日志下中止?

时间:2010-09-01 10:01:56

标签: logging glib

大部分时间我的GLib程序运行良好。但是,当日志像

**(进程: pid ):消息(已递归): blah lah blah

出现,程序将中止。

GLib手册说G_LOG_FLAG_RECURSION默认为致命。

但我无法理解“递归消息”是什么意思?何时会出现递归消息?

由于

2 个答案:

答案 0 :(得分:3)

通过glib / gmessages.c略过,给我的印象非常强烈,即如果G_LOG_FLAG_RECURSION需要记录错误本身就设置了g_logv()

考虑耗尽内存;当内存分配尝试失败时,程序将尝试记录内存分配失败,并可能退出。当日志记录例程尝试分配内存以记录消息时,它可能会失败。因此,日志记录例程会跟踪它们被调用的“深度”,以及切换内存分配策略(它们是在堆栈而不是在堆上分配),如果它是递归日志记录调用的话。

只要日志记录例程收到错误消息并且想要记录错误,真的错误就会发生,所以尝试使用其他机制登录然后退出是有意义的。

所以你可能只是看到了真正问题的一个遥远的症状。您可以使用ltrace(1)来尝试发现问题,或者您可以启用核心转储(ulimit -c unlimited)并尝试使用gdb的bt命令找到导致程序崩溃的调用链。

答案 1 :(得分:3)

请注意,如果要注册自定义处理程序(使用g_log_set_handler)并且该处理程序(或其中一个被调用者)尝试通过调用记录错误,也会发生对g_ *日志记录例程的递归调用到g_ *例程。

另请注意,glib决定任何递归也应该是致命的(即使只有一个深度的非无限)。对于sarnold对内部失败递归的回答中所描述的情况,这当然有意义,但在尝试修复自定义处理程序重复出现的问题时可能并不明显。因此,glib会在第一次递归调用g_ *之前检测到递归;它甚至不会检查您的自定义处理程序是否已附加。因此,您永远不会看到对您的处理程序的递归调用。所有这些意味着在处理程序的主体(以及类似的东西)内小心地取消注册处理程序的努力是徒劳的。

你必须确保自定义处理程序调用堆栈中的任何内容都不会调用g_ *例程(如果你处理对外部代码的调用会变得棘手,并且会使得尝试将日志消息传递到远程目的地或其他东西)。