使用mongoc_cursor_next()迭代时Mongo C Driver游标内存泄漏问题
MongoDB C Driver 1.25.1 大集合同步内存持续增长OOM问题排查
问题场景
使用Mongo C Driver 1.25.1在Docker容器中运行进程,因无法使用mongodump/mongorestore,需手动同步两个数据库的所有集合。核心代码逻辑如下:
bson_t filter = BSON_INITIALIZER; mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(collectionRemote, &filter, NULL, NULL); bson_destroy(&filter); const bson_t *doc; if (sync_individual_documents) { mongoc_cursor_set_batch_size(cursor,(uint32_t)1); while(mongoc_cursor_next(cursor, &doc)) { // 处理文档逻辑 } } else { mongoc_cursor_set_batch_size(cursor,(uint32_t)1000); while(mongoc_cursor_next(cursor, &doc)) { // 处理文档逻辑 } } mongoc_cursor_destroy(cursor); return;
该代码遍历每个集合执行,小集合场景内存可正常回收,但处理大文档/多文档的大集合时,调用mongoc_cursor_next()后内存持续增长,销毁游标也无法释放,多次执行触发OOM。已用Valgrind、ASAN检测未发现泄漏,MongoDB官网无相关泄漏记录。
排查方向与解决办法
调整batchSize设置时机
当前代码创建游标后再修改batchSize,可能导致游标内部已初始化的缓冲区与设置的batchSize不匹配,引发内存累积。建议在创建游标时通过find选项指定batchSize:bson_t filter = BSON_INITIALIZER; bson_t *find_opts = bson_new(); BSON_APPEND_INT32(find_opts, "batchSize", sync_individual_documents ? 1 : 1000); mongoc_cursor_t *cursor = mongoc_collection_find_with_opts(collectionRemote, &filter, find_opts, NULL); bson_destroy(find_opts); bson_destroy(&filter);强制回收BSON内存池
Mongo C Driver使用内置内存池管理BSON对象内存,游标销毁后部分空闲内存可能未立即归还给系统,导致进程内存占用居高不下。可在销毁游标后手动触发内存池清理:mongoc_cursor_destroy(cursor); bson_mem_pool_cleanup(); // 强制回收BSON内存池空闲内存检查文档处理逻辑
确认//处理文档逻辑中是否存在隐性内存泄漏:- 如果调用了
bson_copy(doc)或bson_dup(doc),必须在使用完后调用bson_destroy()销毁复制后的对象; - 避免对
doc指针的长期引用,确保每次循环后无残留引用。
- 如果调用了
尝试升级Driver版本
1.25.1之后的版本可能修复了游标内存管理的隐性问题,建议升级至最新稳定版(如1.26.x)验证问题是否解决。优化大文档处理逻辑
针对超大文档,可通过find选项设置cursorType: "tailable"或noCursorTimeout配合分批处理,启用流模式避免一次性加载过大的文档到内存中。
内容的提问来源于stack exchange,提问作者cdevto
相关产品推荐
相关产品推荐

