ほとんどの場合、私の GLib プログラムは問題なく動作します。ただし、ログが次のようになると
** (プロセス: pid ): メッセージ (再帰):何とか何とか
と表示され、プログラムは中止されます。
GLib マニュアルによると、G_LOG_FLAG_RECURSION はデフォルトで致命的と見なされます。
しかし、「再帰メッセージ」が何を意味するのか理解できませんか? 再帰メッセージはいつ発生しますか?
ありがとう
glib/gmessages.c にざっと目を通してみると、エラー自体をログに記録する必要がG_LOG_FLAG_RECURSION
ある場合に設定されている非常に強い印象を受けます。g_logv()
メモリ不足を考慮してください。メモリ割り当ての試行が失敗すると、プログラムはメモリ割り当ての失敗をログに記録しようとし、おそらく終了します。ロギング ルーチンがメッセージをログに記録するためにメモリを割り当てようとすると、おそらく失敗します。そのため、ロギング ルーチンは、呼び出しの「深さ」を追跡し、再帰的なロギング呼び出しの場合、メモリ割り当て戦略を切り替えます (ヒープではなくスタックに割り当てます)。
ログ ルーチンがエラー メッセージを受け取り、エラーをログに記録したい場合は常に、何か非常に悪いことが起こっているため、別のメカニズムでログを記録してから終了することは理にかなっています。
したがって、実際の問題からは程遠い症状が見られているだけかもしれません。を使用ltrace(1)
して問題を特定するか、コア ダンプ ( ) を有効にして、gdb のコマンドulimit -c unlimited
を使用してプログラムをクラッシュさせるコール チェーンを見つけようとすることができます。bt
g_* ロギング ルーチンへの再帰呼び出しは、カスタム ハンドラを ( を使用してg_log_set_handler
) 登録し、そのハンドラ (またはその呼び出し先の 1 つ) が g_* ルーチンへの呼び出しでエラーをログに記録しようとする場合にも発生する可能性があることに注意してください。
また、glib は再帰も致命的であると判断したことに注意してください (たとえ 1 レベルの深さの非無限であっても)。これは、sarnold's answer of recursion on internal failure で説明されているケースでは確かに理にかなっていますが、カスタム ハンドラーが繰り返し発生する場合の問題を修正しようとすると、明らかではない可能性があります。そのため、glib は g_* への最初の再帰呼び出しの時点で再帰を検出します。カスタムハンドラーがアタッチされているかどうかを確認することさえできません。したがって、ハンドラーへの再帰呼び出しが表示されることはありません。これはすべて、ハンドラーの本体内でハンドラーを慎重に登録解除するなどの努力 (および同様のこと) が無駄であることを意味します。
カスタム ハンドラーからのコール スタックから g_* ルーチンを呼び出すものがないことを絶対に確認する必要があります (これは、ハンドラーが外部コードへの呼び出しを行い、ログ メッセージをリモートの宛先に配信しようとするなどの複雑な処理を行う場合に注意が必要です)。か何か)。