如何在NodeJS中‘标记’对象以进行垃圾回收

d5vmydt9  于 2022-09-21  发布在  Node.js
关注(0)|答案(1)|浏览(218)

我有一个递归函数:

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);
    }

}

我希望在每次运行后都对对象obj进行GC处理。

我有一个对象属性值分配给一个局部变量(var1),设置obj=null是否会强制在下一个周期中对其进行GC?这意味着在每次运行之后,对象obj会被GC‘ed吗?

如果不是,如何做到这一点?

qacovj5a

qacovj5a1#

由于一些评论者忽略了这可能是递归代码这一事实,我想指出,这个答案是在该递归上下文中编写的。如果它不是递归的,那么就不需要设置obj = null,因为只要函数一返回,变量obj就有资格立即进行Garabage收集。
设置obj=NULL是否会强制在下一个周期中对其进行GC?

假设没有其他代码(如await make_some_api_call();中的代码)具有对obj的任何持久引用,则设置obj = null将清除对该变量的一个引用,并在NodeJS下一次运行垃圾收集循环的时间点使其“有资格”进行垃圾收集。

这可能是也可能不是“每次跑步之后”。您并没有真正描述“每次运行后”是什么意思,因为它与您的代码有关,但是无论如何,垃圾收集器何时运行并没有被精确定义。

NodeJS将在它认为需要以及似乎有时间的时候运行一个GC周期。垃圾收集有时可能有点懒。如果您忙于做很多事情,那么NodeJS将尝试不妨碍您的代码仅仅为了运行GC而进行的工作。它将尝试等待,直到事件循环不再执行任何操作。这是有例外的,但为了避免影响运行时性能,它会在事件循环空闲时寻找机会运行GC。

在您的递归代码中,您确实有一个await,因此假设这需要一些时间来解析它的承诺,那么下一个await可能是NodeJS运行GC周期以清除前一个递归调用中的obj的机会。

我还应该指出,这样的代码也可以用某种循环来编写,而不是使用递归,这有时会简化事情。首先,它防止了堆积。由于没有复杂的本地函数上下文或大量函数参数,因此很容易将其转换为while(more)类型的循环,其中包含await,并在循环内进行某种条件测试,以设置more标志或使用breakreturn在完成时停止循环。如果这可能会多次递归,那么避免堆栈堆积(还包括对递归调用的每个async函数的承诺)可能是有益的。

下面是一些类似的伪代码,可以避免递归并自动重用obj变量(释放对前一个对象的引用可用于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;
    }
}

相关问题