oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
74.13k stars 2.76k forks source link

Memory leak when using Remix #13362

Closed Sendouc closed 2 weeks ago

Sendouc commented 2 months ago

What version of Bun is running?

1.1.25-canary.20+d4237b075

What platform is your computer?

Darwin 23.6.0 arm64 arm

What steps can reproduce the bug?

1) Clone this repo https://github.com/Sendouc/bun-memory-leak-test (default Remix project created via the create-remix CLI with a loader added to the front page route, minimal Bun server and heapStats logging in the entry.server.tsx file) 2)bun run build and then bun run start 3) Generate some load via autocannon: bunx autocannon 'http://localhost:3001/' -d 500 4) Observe the logs

What is the expected behavior?

protectedObjectTypeCounts.Promise does not keep going up indefinitely

What do you see instead?

protectedObjectTypeCounts.Promise keeps going up:

image

Additional information

Specifically this seems to be related to loaders. Before I add a loader to the minimal project there is no behavior like this. Further when I inspect the generateHeapSnapshot() it seems that the "Promises" list contains a lot of loaders.

I've been looking into this after failing to deploy my Bun converted project. It seems that there is a memory leak going which made me revert back to Node.js (in the graph pink is Node.js and others are Bun):

image

So it seems there is something amiss there but the above is just my hypothesis what it could be related to.

Jarred-Sumner commented 2 months ago

protectedObjectCount

Yes, very much sounds like a memory leak.

Jarred-Sumner commented 2 weeks ago

As of Bun v1.1.27, the Promise objects do not stay alive and memory usage stabilizes around 512 MB on my mac and is overall is higher than it should be

This is in Bun v1.1.32 (latest):

{
  objectTypeCounts: {
    Function: 6847,
    string: 6755,
    Structure: 5575,
    UnlinkedFunctionExecutable: 4855,
    FunctionExecutable: 4799,
    Object: 1546,
    JSLexicalEnvironment: 1319,
    FunctionCodeBlock: 1055,
    GetterSetter: 942,
    NativeExecutable: 814,
    StructureRareData: 579,
    SymbolTable: 550,
    UnlinkedFunctionCodeBlock: 535,
    Array: 519,
    "Immutable Butterfly": 353,
    StructureChain: 258,
    PropertyTable: 246,
    FunctionRareData: 191,
    RegExp: 165,
    CustomGetterSetter: 124,
    Uint8Array: 118,
    symbol: 117,
    AsyncFunction: 87,
    Module: 83,
    UnlinkedProgramCodeBlock: 76,
    DOMAttributeGetterSetter: 73,
    ProgramExecutable: 67,
    SparseArrayValueMap: 57,
    Set: 45,
    InternalPromise: 37,
    Map: 29,
    JSPropertyNameEnumerator: 28,
    JSModuleEnvironment: 14,
    JSSourceCode: 14,
    ModuleRecord: 14,
    JSAsyncGeneratorFunction: 10,
    Promise: 10,
    WeakMap: 6,
    Arguments: 5,
    ModuleNamespaceObject: 5,
    ScopedArgumentsTable: 5,
    ModuleProgramExecutable: 4,
    UnlinkedModuleProgramCodeBlock: 4,
    GeneratorFunction: 3,
    TextEncoder: 3,
    ArrayBuffer: 2,
    AsyncGeneratorFunction: 2,
    BigInt: 2,
    BufferList: 2,
    Callee: 2,
    Crypto: 2,
    DebugHTTPServer: 2,
    Headers: 2,
    Iterator: 2,
    MessageChannel: 2,
    NodeJSFS: 2,
    Performance: 2,
    ReadableStreamDefaultController: 2,
    ReadableStreamDefaultReader: 2,
    ReadableStream: 2,
    StringDecoder: 2,
    SubtleCrypto: 2,
    Timeout: 2,
    URLSearchParams: 2,
    URL: 2,
    AbortSignal: 1,
    "Array Iterator": 1,
    AsyncFromSyncIterator: 1,
    AsyncGenerator: 1,
    AsyncIterator: 1,
    BigInt64ArrayPrototype: 1,
    BigUint64ArrayPrototype: 1,
    BlobInternalReadableStreamSource: 1,
    Blob: 1,
    Boolean: 1,
    Buffer: 1,
    Bun: 1,
    CryptoHasher: 1,
    Dirent: 1,
    EventEmitter: 1,
    EventTarget: 1,
    File: 1,
    FinalizationRegistry: 1,
    Float16ArrayPrototype: 1,
    Float32ArrayPrototype: 1,
    Float64ArrayPrototype: 1,
    Generator: 1,
    GlobalObject: 1,
    Int16ArrayPrototype: 1,
    Int32ArrayPrototype: 1,
    Int8ArrayPrototype: 1,
    InternalFieldTuple: 1,
    InternalModuleRegistry: 1,
    InternalPromisePrototype: 1,
    Intl: 1,
    "Iterator Helper": 1,
    JSGlobalLexicalEnvironment: 1,
    JSGlobalProxy: 1,
    JSON: 1,
    "Map Iterator": 1,
    Math: 1,
    ModuleLoader: 1,
    ModulePrototype: 1,
    NextT
    Number: 1,
    ProcessBindingConstants: 1,
    Process: 1,
    Prototype: 1,
    ReadableHTTPResponseSinkController: 1,
    Reflect: 1,
    "RegExp String Iterator": 1,
    Request: 1,
    Response: 1,
    "Set Iterator": 1,
    ShadowRealm: 1,
    Stats: 1,
    "String Iterator": 1,
    String: 1,
    Symbol: 1,
    TextDecoder: 1,
    TextEncoderStreamEncoder: 1,
    Uint16ArrayPrototype: 1,
    Uint32ArrayPrototype: 1,
    Uint8ArrayPrototype: 1,
    Uint8ClampedArrayPrototype: 1,
    WeakRef: 1,
    WeakSet: 1,
    WebAssembly: 1,
    console: 1,
    require: 1,
    resolve: 1,
  },
  protectedObjectTypeCounts: {
    UnlinkedProgramCodeBlock: 76,
    Function: 16,
    UnlinkedModuleProgramCodeBlock: 4,
    AsyncFunction: 1,
    DebugHTTPServer: 1,
    GlobalObject: 1,
    Timeout: 1,
  },
  heapSize: 6781296,
  heapCapacity: 9140608,
  extraMemorySize: 3516656,
  objectCount: 41426,
  protectedObjectCount: 100,
  globalObjectCount: 1,
  protectedGlobalObjectCount: 1,
}
RSS 519

This particular issue is fixed, and I suspect the situation will improve further after #14384 lands