Possible memory leak when used with MongoDB
What version of Bun is running?
1.1.15
What platform is your computer?
Linux 5.10.214-202.855.amzn2.x86_64 x86_64 (Docker alpine image)
What steps can reproduce the bug?
I might be wrong here, but repeated calls to MongoDB through both mongoose and the driver skyrockets memory and CPU usage and doesn't seem to get reclaimed over time. After running out of options I ran the manual garbage collector at a recurring interval which reduced the rate at which memory is getting consumed but the issue still persists. The following drive link contains 3 heap snapshots taken from a running container at very short intervals :-
https://drive.google.com/file/d/1HG-68CdprR_nRwBkFInOOTBkS1VoneNA/view?usp=drive_link
Unfortunately, I do not possess enough knowledge to make head or tail of it except seeing the fact that the number of items in it increases, I would greatly appreciate it if someone could have a look when there's some free time on their hands
What is the expected behavior?
No response
What do you see instead?
No response
Additional information
I managed to isolate all parts of the code and the following is observed :->
If i comment out the mongodb call and say I hardcode and return the same payload, memory usage doesn't increase whatever the number of requests I send
Once it's added back memory usage continues to increase and doesn't drop
I used JMeter to spam requests to test this, but even without spamming only on normal production request rates the behaviour is the same
This is another container, which was not restricted in memory
This is another container, which was not restricted in memory
Apologies, ignore this scenario, tracked it down to a nasty bug in our code a few mins ago
Hello, was there by any chance some time to look into this issue ? Here's a sample script which can reproduce it if that might be of any help ->
import mongoose from 'mongoose'
await mongoose.connect("<MONGO_URI>")
Bun.serve({
port: 2005,
async fetch(req) {
const events = await mongoose.connection.collection("users").find().toArray()
return new Response(JSON.stringify(events));
},
})
FYI:
- This does not happen on NodeJS if i do the same with a node http server
- It happens on MacOS (13.4 /M2 chip) as well apart from the linux platform mentioned above
- It happens on bun 1.1.20 as well
- It happens with multiple versions of mongoose and mongodb, the script below uses mongoose version
8.4.3
Also here are 3 outputs of heapStats() function at the following instances
- As soon as the server is up
{
heapSize: 31349184,
heapCapacity: 33725056,
extraMemorySize: 23100096,
objectCount: 96900,
protectedObjectCount: 451,
globalObjectCount: 1,
protectedGlobalObjectCount: 1,
objectTypeCounts: {
GeneratorFunction: 8,
ModuleProgramExecutable: 2,
JSAsyncGeneratorFunction: 7,
"Array Iterator": 1,
"Set Iterator": 1,
ProcessBindingConstants: 1,
Int16ArrayPrototype: 1,
require: 1,
AsyncGeneratorFunction: 2,
Function: 8918,
Uint8ClampedArrayPrototype: 1,
Request: 2,
RegExp: 245,
ShadowRealm: 1,
JSSourceCode: 7,
JSPropertyNameEnumerator: 10,
UnlinkedFunctionExecutable: 7272,
ModuleProgramCodeBlock: 2,
FunctionExecutable: 7283,
GlobalObject: 1,
Math: 1,
AsyncFromSyncIterator: 1,
Intl: 1,
Crypto: 2,
WebAssembly: 1,
AsyncGenerator: 10,
StructureChain: 512,
TextEncoder: 3,
Dirent: 1,
File: 1,
StructureRareData: 1152,
Blob: 1,
Buffer: 1,
Uint16Array: 6,
Float64Array: 4,
Response: 1,
Uint16ArrayPrototype: 1,
"WebAssembly.Module": 2,
SymbolTable: 1746,
Bun: 1,
StringDecoder: 2,
JSON: 1,
Callee: 2,
ProgramCodeBlock: 387,
Uint32ArrayPrototype: 1,
DebugHTTPServer: 2,
CustomGetterSetter: 107,
console: 1,
"WebAssembly.Memory": 2,
UnlinkedProgramCodeBlock: 420,
ProgramExecutable: 387,
Date: 12,
DataView: 2,
WebAssemblyFunction: 6,
InternalModuleRegistry: 1,
SubtleCrypto: 2,
URL: 3,
WeakRef: 1,
CryptoHasher: 1,
Int32ArrayPrototype: 1,
ModuleLoader: 1,
BigInt: 6,
ModuleRecord: 7,
PropertyTable: 837,
String: 1,
Map: 29,
Boolean: 1,
"Map Iterator": 1,
TextDecoder: 2,
InternalPromise: 16,
"URLSearchParams Iterator": 1,
Array: 11594,
Process: 1,
FinalizationRegistry: 1,
Number: 1,
ModuleNamespaceObject: 4,
URLSearchParams: 2,
Float64ArrayPrototype: 1,
TLSSocket: 5,
"Intl.ListFormat": 1,
NativeExecutable: 796,
DOMAttributeGetterSetter: 72,
Prototype: 1,
Float32ArrayPrototype: 1,
UnlinkedFunctionCodeBlock: 1680,
"WebAssembly.Instance": 2,
FunctionRareData: 302,
JSGlobalProxy: 1,
JSGlobalLexicalEnvironment: 1,
"Immutable Butterfly": 457,
Set: 91,
AsyncFunction: 366,
Promise: 35,
AsyncIterator: 1,
NextTickQueue: 1,
BigUint64ArrayPrototype: 1,
BigInt64ArrayPrototype: 1,
Arguments: 5,
Structure: 11554,
Uint8Array: 471,
UnlinkedModuleProgramCodeBlock: 2,
symbol: 280,
Reflect: 1,
ArrayBuffer: 12,
EventEmitter: 1,
ModulePrototype: 1,
Performance: 2,
JSModuleEnvironment: 8,
InternalPromisePrototype: 1,
Object: 2491,
FunctionCodeBlock: 1731,
"RegExp String Iterator": 1,
Generator: 8,
Int8ArrayPrototype: 1,
ScopedArgumentsTable: 6,
"Intl.DurationFormat": 1,
Timeout: 7,
Symbol: 1,
WebAssemblyModuleRecord: 1,
JSLexicalEnvironment: 1616,
string: 16924,
Iterator: 1,
NodeJSFS: 2,
Module: 443,
Stats: 1,
"String Iterator": 1,
BufferList: 10,
WeakMap: 3,
CryptoKey: 2,
InternalFieldTuple: 1,
resolve: 1,
EventTarget: 1,
Uint8ArrayPrototype: 1,
SparseArrayValueMap: 99,
GetterSetter: 748,
},
protectedObjectTypeCounts: {
UnlinkedModuleProgramCodeBlock: 2,
AsyncFunction: 1,
UnlinkedProgramCodeBlock: 420,
GlobalObject: 1,
DebugHTTPServer: 1,
Function: 23,
Timeout: 3,
},
}
- After 4000 requests ( 4000 find calls)
{
heapSize: 44730009,
heapCapacity: 70790921,
extraMemorySize: 31743577,
objectCount: 198064,
protectedObjectCount: 451,
globalObjectCount: 1,
protectedGlobalObjectCount: 1,
objectTypeCounts: {
GeneratorFunction: 8,
ModuleProgramExecutable: 2,
JSAsyncGeneratorFunction: 7,
"Array Iterator": 1,
"Set Iterator": 1,
ProcessBindingConstants: 1,
Int16ArrayPrototype: 1,
require: 1,
AsyncGeneratorFunction: 2,
Function: 14688,
Uint8ClampedArrayPrototype: 1,
Request: 100,
RegExp: 230,
ShadowRealm: 1,
JSSourceCode: 7,
JSPropertyNameEnumerator: 9,
UnlinkedFunctionExecutable: 7075,
Math: 1,
FunctionExecutable: 6768,
GlobalObject: 1,
AsyncFromSyncIterator: 1,
Intl: 1,
Crypto: 2,
WebAssembly: 1,
AsyncGenerator: 435,
StructureChain: 518,
TextEncoder: 3,
Dirent: 1,
File: 1,
StructureRareData: 1566,
Blob: 1,
Buffer: 1,
Uint16Array: 6,
Float64Array: 4,
Response: 99,
Uint16ArrayPrototype: 1,
"WebAssembly.Module": 2,
JSON: 1,
Bun: 1,
StringDecoder: 2,
SymbolTable: 994,
Callee: 2,
Uint32ArrayPrototype: 1,
DebugHTTPServer: 2,
CustomGetterSetter: 237,
console: 1,
"WebAssembly.Memory": 2,
ProgramExecutable: 387,
UnlinkedProgramCodeBlock: 420,
Date: 5331,
DataView: 245,
WebAssemblyFunction: 6,
InternalModuleRegistry: 1,
SubtleCrypto: 2,
URL: 3,
WeakRef: 1,
CryptoHasher: 1,
Int32ArrayPrototype: 1,
ModuleLoader: 1,
BigInt: 71,
ModuleRecord: 7,
PropertyTable: 1337,
String: 1,
Map: 30,
Boolean: 1,
TextDecoder: 2,
"Map Iterator": 1,
InternalPromise: 16,
"URLSearchParams Iterator": 1,
Array: 21789,
Process: 1,
FinalizationRegistry: 1,
Number: 1,
ModuleNamespaceObject: 4,
URLSearchParams: 2,
Float64ArrayPrototype: 1,
TLSSocket: 70,
"Intl.ListFormat": 1,
NativeExecutable: 800,
DOMAttributeGetterSetter: 72,
Prototype: 1,
Float32ArrayPrototype: 1,
"WebAssembly.Instance": 2,
UnlinkedFunctionCodeBlock: 692,
FunctionRareData: 485,
JSGlobalProxy: 1,
JSGlobalLexicalEnvironment: 1,
"Immutable Butterfly": 441,
Set: 91,
AsyncFunction: 366,
Promise: 2252,
AsyncIterator: 1,
NextTickQueue: 1,
BigUint64ArrayPrototype: 1,
BigInt64ArrayPrototype: 1,
Arguments: 8,
Uint8Array: 6564,
Structure: 14119,
UnlinkedModuleProgramCodeBlock: 2,
symbol: 280,
Reflect: 1,
ArrayBuffer: 374,
EventEmitter: 1,
ModulePrototype: 1,
Performance: 2,
JSModuleEnvironment: 8,
InternalPromisePrototype: 1,
Object: 30291,
FunctionCodeBlock: 1160,
"RegExp String Iterator": 1,
Generator: 1059,
Int8ArrayPrototype: 1,
ScopedArgumentsTable: 1,
"Intl.DurationFormat": 1,
Timeout: 10,
Symbol: 1,
WebAssemblyModuleRecord: 1,
JSLexicalEnvironment: 5726,
string: 29284,
Iterator: 1,
NodeJSFS: 2,
Module: 443,
Stats: 1,
"String Iterator": 1,
BufferList: 140,
WeakMap: 3,
CryptoKey: 2,
InternalFieldTuple: 1,
resolve: 1,
Uint8ArrayPrototype: 1,
EventTarget: 1,
SparseArrayValueMap: 164,
GetterSetter: 748,
},
protectedObjectTypeCounts: {
UnlinkedModuleProgramCodeBlock: 2,
AsyncFunction: 1,
UnlinkedProgramCodeBlock: 420,
GlobalObject: 1,
DebugHTTPServer: 1,
Function: 23,
Timeout: 3,
},
}
- 10 minutes after above 4000 requests ( Server is idle the whole time)
{
heapSize: 49598041,
heapCapacity: 71965625,
extraMemorySize: 32901897,
objectCount: 276971,
protectedObjectCount: 451,
globalObjectCount: 1,
protectedGlobalObjectCount: 1,
objectTypeCounts: {
GeneratorFunction: 8,
ModuleProgramExecutable: 2,
JSAsyncGeneratorFunction: 7,
"Array Iterator": 1,
"Set Iterator": 1,
ProcessBindingConstants: 1,
Int16ArrayPrototype: 1,
require: 1,
AsyncGeneratorFunction: 2,
Function: 18256,
Uint8ClampedArrayPrototype: 1,
Request: 100,
RegExp: 230,
ShadowRealm: 1,
JSSourceCode: 7,
JSPropertyNameEnumerator: 9,
UnlinkedFunctionExecutable: 7075,
Math: 1,
FunctionExecutable: 6768,
GlobalObject: 1,
AsyncFromSyncIterator: 1,
Intl: 1,
Crypto: 2,
WebAssembly: 1,
AsyncGenerator: 1020,
StructureChain: 518,
TextEncoder: 3,
Dirent: 1,
File: 1,
StructureRareData: 1577,
Blob: 1,
Buffer: 1,
Uint16Array: 6,
Float64Array: 4,
Response: 99,
Uint16ArrayPrototype: 1,
"WebAssembly.Module": 2,
JSON: 1,
Bun: 1,
StringDecoder: 2,
SymbolTable: 994,
Callee: 2,
Uint32ArrayPrototype: 1,
DebugHTTPServer: 2,
CustomGetterSetter: 237,
console: 1,
"WebAssembly.Memory": 2,
ProgramExecutable: 387,
UnlinkedProgramCodeBlock: 420,
Date: 6519,
DataView: 1084,
WebAssemblyFunction: 6,
InternalModuleRegistry: 1,
SubtleCrypto: 2,
URL: 3,
WeakRef: 1,
CryptoHasher: 1,
Int32ArrayPrototype: 1,
ModuleLoader: 1,
BigInt: 71,
ModuleRecord: 7,
PropertyTable: 1357,
String: 1,
ArrayIterator: 39,
Map: 182,
Boolean: 1,
TextDecoder: 2,
"Map Iterator": 1,
InternalPromise: 16,
"URLSearchParams Iterator": 1,
Array: 35118,
Process: 1,
FinalizationRegistry: 1,
Number: 1,
ModuleNamespaceObject: 4,
URLSearchParams: 2,
Float64ArrayPrototype: 1,
TLSSocket: 70,
"Intl.ListFormat": 1,
NativeExecutable: 800,
DOMAttributeGetterSetter: 72,
Prototype: 1,
Float32ArrayPrototype: 1,
"WebAssembly.Instance": 2,
UnlinkedFunctionCodeBlock: 692,
FunctionRareData: 680,
JSGlobalProxy: 1,
JSGlobalLexicalEnvironment: 1,
"Immutable Butterfly": 630,
Set: 103,
AsyncFunction: 366,
Promise: 4265,
AsyncIterator: 1,
NextTickQueue: 1,
BigUint64ArrayPrototype: 1,
BigInt64ArrayPrototype: 1,
Arguments: 28,
Uint8Array: 9226,
Structure: 14300,
UnlinkedModuleProgramCodeBlock: 2,
symbol: 280,
Reflect: 1,
ArrayBuffer: 817,
EventEmitter: 1,
ModulePrototype: 1,
Performance: 2,
JSModuleEnvironment: 8,
InternalPromisePrototype: 1,
Object: 52262,
FunctionCodeBlock: 1202,
"RegExp String Iterator": 1,
Generator: 1293,
Int8ArrayPrototype: 1,
ScopedArgumentsTable: 1,
"Intl.DurationFormat": 1,
Timeout: 205,
Symbol: 1,
WebAssemblyModuleRecord: 1,
JSLexicalEnvironment: 8752,
string: 35128,
Iterator: 1,
NodeJSFS: 2,
Module: 443,
Stats: 1,
"String Iterator": 1,
BufferList: 140,
WeakMap: 3,
CryptoKey: 2,
InternalFieldTuple: 1,
resolve: 1,
Uint8ArrayPrototype: 1,
EventTarget: 1,
SparseArrayValueMap: 164,
GetterSetter: 748,
},
protectedObjectTypeCounts: {
UnlinkedModuleProgramCodeBlock: 2,
AsyncFunction: 1,
UnlinkedProgramCodeBlock: 420,
GlobalObject: 1,
DebugHTTPServer: 1,
Function: 23,
Timeout: 3,
},
}
Yes, when I use mongoose, even if there is not much data, the memory consumption is also very high.
I happened to notice this as well, might help find the issue, the memory usage is stable if I connect to a local database, but keeps increasing if i connect to one on Atlas and also on another service i tried for testing named ScaleGrid
When i tested with the local database I configured ssl in it to check whether enabling ssl is causing the issue, though it seems that it is stable with both ssl enabled, though I'm not sure that it's behavior's the same as when connecting to atlas
Just to be fully sure, I tried building bun locally and trying to replace the tls module which seems to be implemented in Bun with Nodejs, though I wasn't able to get it done since I'm not really familiar with what's going on in the code and I don't have much time to keep at it anymore, please help out here if possible @Jarred-Sumner @cirospaciari
We added some fixes into sockets, can you try bun upgrade --canary and check if is still happening?
We added some fixes into sockets, can you try bun
upgrade --canaryand check if is still happening?
Sorry for the late reply. I tried what you suggested, as well as bun 1.1.22 but the issue still persists
Hello, was it possible by any chance to have a look at this ?
Experiencing this issue even on latest (v1.1.34). Surprised this has not been fixed yet.
Still happening even on v1.2.1
Still happening even on v1.2.4 too, using MongoDB driver.
We're rewriting our node:net implementation with a goal of ~100% of Node.js' tests for node:net to pass in Bun. We expect that to fix many issues like this.
Looks like memory leak with MongoDB + mongoose is still present in 1.2.5
Any updates?
This is another container, which was not restricted in memory