我有一个递归函数:
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吗?
如果不是,如何做到这一点?
1条答案
按热度按时间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
标志或使用break
或return
在完成时停止循环。如果这可能会多次递归,那么避免堆栈堆积(还包括对递归调用的每个async
函数的承诺)可能是有益的。下面是一些类似的伪代码,可以避免递归并自动重用
obj
变量(释放对前一个对象的引用可用于GC):