Home > OS >  how to 'mark' an Object for garbage collection in NodeJS
how to 'mark' an Object for garbage collection in NodeJS

Time:09-22

I have a recursive function:

const fn = async (val) => {
    let obj = await make_some_api_call();
    // example response {a: 'apple', b : 'bbb', c: 'ccc', d: 'ddd'};

    if ('a' in obj) {
        const var1 = obj.a;
        obj = null;
        return fn(var1);
    }
    
}

I want the Object obj to be gc'ed after each run.

I have a Object property value assigned to a local variable (var1), will setting obj=null force it to be gc'ed in next cycle? Meaning after each run will Object obj get gc'ed?

If not, how to achieve this?

CodePudding user response:

Since some commentors have missed the fact that this is potentially recursive code, I want to point out that this answer is written in that recursive context. If it wasn't recursive, then setting obj = null would not be necessary because the variable obj would immediately be eligible for garabage collection anyway as soon as the function returned.

will setting obj=null force it to be gc'ed in next cycle?

Assuming that no other code such as code inside of await make_some_api_call(); has any persistent references to obj, then setting obj = null will clear your one reference to that variable and will make it "eligible" for garbage collection at the point in time where nodejs next runs a garbage collection cycle.

That may or may not be "after each run". You don't really describe what "after each run" means as it pertains to your code, but in any case, when the garbage collector runs is not precisely defined.

Nodejs will run a GC cycle when it thinks it needs to and when it appears to have time to. Garbage collection can sometimes be a bit lazy. If you're busy doing a lot of things, then nodejs will attempt to not get in the way of what your code is doing just to run the GC. It will try to wait until the event loop isn't really doing anything. There are exceptions to this, but to avoid impacting run-time performance, it looks for opportunities to run GC when the event loop is idle.

In your recursive code, you do have an await so assuming that takes some amount of time to resolve its promise, then that next await could be an opportunity for nodejs to run the GC cycle to clean up the obj from the prior recursive call.


I should also point out that code like this can also be written with some sort of loop instead of using recursion and that sometimes simplifies things. For one, it prevents stack-build up. Since there is no complicated local function context or lots of function arguments, this could easily be turned into a while(more) kind of loop with the await and some sort of condition test inside the loop that either sets the more flag or uses break or return to stop the looping when done. If this may recurse many times, just avoiding the stack build-up (which also includes a promise for each async function called recursively) could be beneficial.

Here's some similar pseudo-code that avoids the recursion and automatically reuses the obj variable (freeing the reference to the prior object to it is available for GC):

const fn = async (val) => {
    // value for the first one comes from the function argument,
    // subsequent iterations get the value from the prior call
    let var1 = val;
    let obj;
    while (true) {
        obj = await make_some_api_call(var1);
        if (!('a' in obj)) {
            // all done
            break;
        }
        // run again using obj.a
        var1 = obj.a;
    }
}
  • Related