Uploaded image for project: 'Node.js Driver'
  1. Node.js Driver
  2. NODE-5729

If you don't use a cursor it seems to leak memory.

    • Type: Icon: Bug Bug
    • Resolution: Duplicate
    • Priority: Icon: Unknown Unknown
    • None
    • Affects Version/s: None
    • Component/s: None
    • 2
    • Not Needed
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?

      What problem are you facing?

      Through doing some heap snapshots I realised that when we call db.collection.find() repeatedly in a for or while loop in mongosh the ClientSession, FindCursor and MongoDBCollectionNamespace objects left on the heap grow by the number of loop iterations minus 1 every time.

      I realised that this is because only the last cursor is used by the shell to output something. ie.

      test> db.test.insertOne({})
      {
        acknowledged: true,
        insertedId: ObjectId('6548dd7f12760d8147f865b0')
      }
      test> for (let i=0; i<10; i++) {db.test.find();}
      [ { _id: ObjectId('6548dd7f12760d8147f865b0') } ]
      

      What driver and relevant dependency versions are you using?

      mongodb driver version 6.2.0

      Steps to reproduce?

      This is just the example from the driver README with the while loop added.

      const { MongoClient } = require('mongodb');
      // or as an es module:
      // import { MongoClient } from 'mongodb'
      
      // Connection URL
      const url = 'mongodb://localhost:27017';
      const client = new MongoClient(url);
      
      // Database Name
      const dbName = 'myProject';
      
      async function main() {
        // Use connect method to connect to the server
        await client.connect();
        console.log('Connected successfully to server');
        const db = client.db(dbName);
        const collection = db.collection('documents');
      
        // the following code examples can be pasted here...
        while (true) {
          collection.find({}); // note: not doing anything with the cursor
        }
      
        return 'done.';
      }
      
      main()
        .then(console.log)
        .catch(console.error)
        .finally(() => client.close());
      

      The quickest way to get this to fail is by giving it little memory:

      NODE_OPTIONS=--max-old-space-size=64 node index.js
      Connected successfully to server
      
      <--- Last few GCs --->
      ca[32214:0x7fd638008000]      516 ms: Mark-sweep (reduce) 63.3 (65.7) -> 62.8 (66.2) MB, 14.8 / 0.0 ms  (+ 8.6 ms in 15 steps since start of marking, biggest step 2.5 ms, walltime since start of marking 26 ms) (average mu = 0.386, current mu = 0.223) alloca[32214:0x7fd638008000]      545 ms: Mark-sweep (reduce) 63.1 (66.2) -> 62.9 (66.5) MB, 21.8 / 0.0 ms  (+ 2.6 ms in 3 steps since start of marking, biggest step 1.6 ms, walltime since start of marking 25 ms) (average mu = 0.294, current mu = 0.179) allocat
      
      <--- JS stacktrace --->
      
      FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
       1: 0x107560e05 node::Abort() [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       2: 0x107560ff5 node::OOMErrorHandler(char const*, bool) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       3: 0x1076cc790 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       4: 0x1076cc753 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       5: 0x10786b125 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       6: 0x10786998c v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       7: 0x107876300 v8::internal::Heap::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       8: 0x107876381 v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
       9: 0x1078431f7 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
      10: 0x107bf14df v8::internal::Runtime_AllocateInOldGeneration(int, unsigned long*, v8::internal::Isolate*) [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
      11: 0x107f92819 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
      12: 0x10ca86e62
      13: 0x107f22905 construct_stub_create_deopt_addr [/Users/leroux.bodenstein/.nvm/versions/node/v16.20.2/bin/node]
      14: 0x10caa0d14
      zsh: abort      NODE_OPTIONS=--max-old-space-size=64 node index.js
      

            Assignee:
            neal.beeken@mongodb.com Neal Beeken
            Reporter:
            leroux.bodenstein@mongodb.com Le Roux Bodenstein
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: