【问题标题】:How to fix settimeout memory leak problem in javascript如何修复javascript中的settimeout内存泄漏问题
【发布时间】:2019-05-06 01:00:17
【问题描述】:

我有一个这样的JS函数

function check() {
    ...do something
}

现在,我想在脚本启动时和每天开始时(每天 00:00:01)运行它。我的代码现在看起来像这样

function check() {
    ...do something

    let today = new Date();
    let tomorrow = new Date();
        tomorrow.setHours(0,0,1,0);
        tomorrow.setDate(tomorrow.getDate()+1);

    console.log("next check in", tomorrow-today);
    setTimeout(() => { check() }, tomorrow-today);
}
check();

我在 check() 中使用 setTimeout。我认为这是糟糕的代码,因为它会创建一个循环,并且函数 check() 永远不会被清理。如何解决?

【问题讨论】:

  • check() 永远不会被清理”是什么意思?你觉得什么是占用内存?你有没有做过任何分析来证明这里有内存泄漏?
  • 其实我并没有进行分析来证明存在内存泄漏。我认为检查功能需要等待 setTimeout 完成,然后才能将其销毁。但是 setTimeout 调用另一个 check() 函数,它将永远等待(调用另一个检查等等)。因此,加载到内存中的每个 check() 函数都不会被销毁。我说的对吗?
  • 听起来你觉得可能的问题是堆栈溢出。请参阅答案以了解为什么 setTimeout() 循环不会导致堆栈溢出。

标签: javascript memory-leaks settimeout


【解决方案1】:

您是对的,由于堆栈无限增长,不受控制的递归可能会导致资源耗尽。例如,下面的 Javascript 程序会在 check() 在没有第一个 returning 的情况下执行足够多次后崩溃:

function check() {
  check();
}
check();

下面的代码不会这样崩溃:

function check() {
  setTimeout(check, 1000);
}
check();

这段代码可以无限期地运行而不会耗尽堆栈,因为每次运行check(),它都可以运行到完成,而return在以后运行之前。

这是因为setTimeout() 函数不直接运行check()。相反,它告诉 Javascript 运行时安排在未来 1 秒内执行 check()。当它和check() 完成后,Javascript 堆栈变为空。 1s 后,check() 的执行排队,最终执行,只要 Javascript 栈是清空的。

由于必须在check() 运行之前清除 Javascript 堆栈,因此避免了堆栈溢出。

【讨论】:

  • setTimeout(check, 1000);setTimeout(() => { check() }, 1000); 之间有什么不同。第二个会不会导致栈溢出
  • ...什么...之间有什么区别吗? :)
  • 我在一个类中编写了这个函数,所以 setTimeout 会是这样的:setTimeout(this.check.bind(this), 1000);setTimeout(() => { this.check() }, 1000);,有关系吗?仍然没有内存泄漏?
  • setTimeout() 将提供的回调作为函数运行并且不提供任何参数,通常您可以直接将函数传递给setTimeout()。如果您传递给setTimeout() 的函数实际上是对象的方法,则需要将对象绑定到函数。因此,在这种情况下,您提供的两种方式中的任何一种都将导致this 在执行this.check() 时正确绑定到对象。而且不会有任何堆栈溢出* * - 因为check() 需要能够访问它关闭的任何变量,check() 使用的任何对象都将保留在内存中。
  • ^ 但这不会是内存泄漏,除非 check() 正在访问的大小正在增长,或者 check() 并不真的需要访问它。
【解决方案2】:

你可以添加函数 clearTimeout(timer):

let timer = setTimeout(() => check());

clearTimeout(timer);

【讨论】:

  • 不正确。我想每天 00:00:01 运行函数(脚本永远运行)。这就是为什么我需要延迟 setTimeout(check, tomorrow-today)
猜你喜欢
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 2012-12-19
相关资源
最近更新 更多