使用g_log_structured向Linux系统日志输出时出现内存泄漏求助
Glib g_log_structured 内存泄漏与段错误问题排查
我在Ubuntu系统上使用Glib 2.76.1实现向系统日志(journald)输出结构化日志,测试了三种实现方式后发现,调用g_log_structured()时频繁出现内存访问错误和内存泄漏,而g_log_structured_array()和直接调用g_log_writer_journald()的方式都能正常工作。
相关代码如下:
#define G_LOG_USE_STRUCTURED #define G_LOG_DOMAIN "MyDomain" #include <glib.h> #include <stdio.h> int main(int argc, char *argv[]) { g_log_set_writer_func (g_log_writer_journald, NULL, NULL); /* regularly leads to a memory leak. g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "CODE_FILE", "mysource.c", "CODE_LINE", 312, "MESSSAGE_ID", "06d4df59e6c24647bfe69d2c27ef0b4e", "MESSAGE", "You have %d eggs", 12 + 2); */ /* The following log message will go to journald */ const GLogField fields[] = { {"MESSAGE", "This is the message", -1}, {"EIGENES_FELD", "mysource.c", -1}, {"STATUS", "3",-1}, }; // works g_log_structured_array (G_LOG_LEVEL_DEBUG, fields,G_N_ELEMENTS (fields)); // works GLogWriterOutput result = g_log_writer_journald ( G_LOG_LEVEL_INFO, fields, G_N_ELEMENTS(fields), NULL); return 0; }
出现的段错误日志:
Okt 19 14:44:05 holger kernel: a.out[12281]: segfault at 138 ip 00007fe6b6b7401d sp 00007ffe746157e8 error 4 in libc.so.6[7fe6b6a22000+178000] likely on CPU 1 (core 1, socket 0) Okt 19 14:44:05 holger kernel: Code: 00 00 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 89 f8 48 89 fa c5 f9 ef c0 25 ff 0f 00 00 3d e0 0f 00 00 0f 87 33 01 00 00 <c5> fd 74 0f c5 fd d7 c1 85 c0 74 57 f3 0f bc c0 c5 f8 77 c3 66 66
问题原因与处理经验
参数格式错误是核心问题
注释的g_log_structured()调用存在两处致命错误:- 字段名拼写错误:
MESSSAGE_ID多写了一个S,正确应为MESSAGE_ID; MESSAGE字段的参数传递逻辑错误:g_log_structured()的可变参数是键值对序列,而非printf的格式化参数。你传递的"You have %d eggs", 12 + 2会被解析为"You have %d eggs"作为键、整数14作为值的无效键值对,直接破坏函数内部的参数解析逻辑,引发内存访问越界和段错误。
- 字段名拼写错误:
内存泄漏由参数错误引发
参数解析混乱会导致Glib内部内存管理逻辑出错,进而触发内存泄漏。修复参数格式后,这类内存泄漏通常会自动消失。修复后的示例代码
修正参数后的g_log_structured()调用如下:g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "CODE_FILE", "mysource.c", "CODE_LINE", GINT_TO_POINTER(312), "MESSAGE_ID", "06d4df59e6c24647bfe69d2c27ef0b4e", "MESSAGE", "You have 14 eggs", NULL);若要使用格式化字符串,需提前拼接完成或用GVariant传递:
gchar *msg = g_strdup_printf("You have %d eggs", 12 + 2); g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "CODE_FILE", "mysource.c", "CODE_LINE", GINT_TO_POINTER(312), "MESSAGE_ID", "06d4df59e6c24647bfe69d2c27ef0b4e", "MESSAGE", msg, NULL); g_free(msg);关键注意点:
- 整数类型字段值必须用
GINT_TO_POINTER()包装; - 可变参数必须以
NULL结尾,标记键值对序列结束; - 不支持直接传递printf式的格式化参数,需提前处理字符串。
- 整数类型字段值必须用
版本相关问题参考
Glib 2.76.x确实存在少量结构化日志的边界场景bug,但大多与参数错误相关。若修复参数后仍有问题,建议升级到Glib 2.78及以上版本,官方在后续版本中修复了部分内存管理相关的问题。
内容的提问来源于stack exchange,提问作者Holger
相关产品推荐
相关产品推荐

