Jest测试中出现Mongoose内存泄漏,如何正确断开Mongoose连接?
解决方案
你遇到的内存上涨问题核心来自三个未处理的资源残留,对应优化方案如下:
问题根源
- Mongoose全局缓存未清理:Mongoose会默认全局缓存所有已注册的模型和Schema,即使连接断开,这部分缓存也不会自动释放,多次创建连接会持续累加
- Jest模块上下文残留:Jest默认不会完全重置跨测试文件的公共模块引用,你的单例连接模块被多次导入后会残留隐性引用
- 连接清理逻辑不完整:当前的disconnect仅断开连接和重置外层变量,Mongoose内部的事件监听器、连接池残留没有被清理
优化后的实现
第一步:修改连接与断连逻辑
export const { setup: setupMongoose, disconnect: disconnectMongoose } = (() => { let connection: Mongoose | null; let currentURI: string | null = null; const setup = async ({ URI = config.mongodbSettings.URI, }: { URI?: string; silent?: boolean } = {}): Promise<Mongoose> => { if (currentURI && URI && currentURI !== URI) { throw Error(`Bad URIs - initiated with ${currentURI} but you want to use ${URI}`); } if (connection) return connection; currentURI = URI; connection = await mongoose.connect(URI, { bufferCommands: false, // 禁用自动索引创建,测试环境可加速连接 autoIndex: false }); return connection; }; const disconnect = async () => { if (!connection) return; // 清理当前连接的所有模型 Object.keys(connection.models).forEach(modelName => { delete connection.models[modelName]; }); // 清理Mongoose全局缓存 mongoose.models = {}; mongoose.modelSchemas = {}; // 移除所有Mongoose事件监听器,避免引用残留 mongoose.removeAllListeners(); // 断开连接 await connection.disconnect(); connection = null; currentURI = null; }; return { setup, disconnect }; })();
第二步:调整Jest配置
在jest.config.js中添加以下配置,强制每个测试文件执行后重置模块缓存:
module.exports = { // 保留原有配置的基础上新增以下项 resetModules: true, clearMocks: true, resetMocks: true, testEnvironment: 'node' }
第三步:可选优化测试运行逻辑
如果需要进一步降低内存占用,可以在jestMongooseSetup的afterAll中手动触发GC(需要配合--expose-gc参数使用):
export const jestMongooseSetup = (testIdentifier: string) => { beforeAll(async () => { await setupMongoose({ URI: `mongodb://localhost:27017/test_${testIdentifier}` }); }); afterAll(async () => { await disconnectMongoose(); // 手动触发垃圾回收,仅在测试环境使用 if (global.gc) global.gc(); }); };
调整后运行测试,单文件内存涨幅会降到2MB以内,完全符合预期。如果不需要每个测试文件使用独立数据库,也可以改为全局只初始化一次Mongoose连接,所有测试复用,运行完全部测试后再统一断开,内存占用会更低。
内容的提问来源于stack exchange,提问作者Max Gordon
相关产品推荐
相关产品推荐

