bun icon indicating copy to clipboard operation
bun copied to clipboard

Possible memory leak when used with MongoDB

Open Akalanka47000 opened this issue 1 year ago • 47 comments

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

Akalanka47000 avatar Jun 24 '24 12:06 Akalanka47000

image This is the memory usage of an example container just in case it may be helpful. The 3 quick drops correspond to container restarts due to hitting the maximum memory limit that I've defined for now. This is within a span of 4 days

Akalanka47000 avatar Jun 29 '24 10:06 Akalanka47000

image

This is another container, which was not restricted in memory

Akalanka47000 avatar Jun 29 '24 14:06 Akalanka47000

image 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

Akalanka47000 avatar Jun 29 '24 17:06 Akalanka47000

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

  1. 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,
  },
}
  1. 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,
  },
}
  1. 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,
  },
}

Akalanka47000 avatar Jul 18 '24 05:07 Akalanka47000

Yes, when I use mongoose, even if there is not much data, the memory consumption is also very high.

mrtime39 avatar Jul 18 '24 08:07 mrtime39

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

Akalanka47000 avatar Jul 24 '24 13:07 Akalanka47000

We added some fixes into sockets, can you try bun upgrade --canary and check if is still happening?

cirospaciari avatar Aug 06 '24 16:08 cirospaciari

We added some fixes into sockets, can you try bun upgrade --canary and 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

Akalanka47000 avatar Aug 08 '24 14:08 Akalanka47000

Hello, was it possible by any chance to have a look at this ?

Akalanka47000 avatar Sep 03 '24 15:09 Akalanka47000

Experiencing this issue even on latest (v1.1.34). Surprised this has not been fixed yet.

aidendotgg avatar Nov 02 '24 22:11 aidendotgg

Still happening even on v1.2.1

Akalanka47000 avatar Jan 28 '25 15:01 Akalanka47000

Still happening even on v1.2.4 too, using MongoDB driver.

chartliex avatar Mar 06 '25 00:03 chartliex

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.

Jarred-Sumner avatar Mar 06 '25 07:03 Jarred-Sumner

Looks like memory leak with MongoDB + mongoose is still present in 1.2.5

cesargdm avatar Mar 13 '25 03:03 cesargdm

Any updates?

trevormil avatar May 03 '25 11:05 trevormil