【问题标题】:Javascript recursion, memory leak?Javascript递归,内存泄漏?
【发布时间】:2021-04-27 02:16:46
【问题描述】:

我正在尝试实现一个每秒执行一次操作的类,它按预期工作,但我不确定内存泄漏。我正在编写的这段代码将有几个月的正常运行时间。

下面的代码是否会导致内存泄漏,因为它在技术上是永无止境的递归?

class Algorithm{
  constructor(){
    //there will be many more things in this constructor
    //which is why this is a class
    const pidTimer = (r,e=0,y=Date.now()-r) => {
      this.someFunction();
      const now = Date.now();
      const dy = now-y;
      const err = e+r-dy
      const u = err*0.2;
      //console.log(dy)
      setTimeout(()=>{pidTimer(r,err,now)},r+u);
    }
    pidTimer(1000);
  }

  someFunction = () => {}
}

【问题讨论】:

    标签: node.js recursion memory-leaks timer


    【解决方案1】:

    这不是那种有任何堆栈积累的递归,因为之前的pidTimer() 函数调用在setTimeout() 触发并再次调用pidTimer() 之前返回。我什至不会调用这个递归(它是预定的重复调用),但这更像是一个语义问题。

    所以,我看到的唯一可能存在内存泄漏或过度使用的地方是 this.someFunction(); 内部,这只是因为您没有向我们展示那里的代码来评估它并查看它的作用。您为pidTimer() 向我们展示的代码本身没有问题。

    【讨论】:

      【解决方案2】:

      现代异步原语

      您拥有的当前功能没有任何“错误”,但我认为它可以得到显着改进。 JavaScript 提供了一个现代化的异步原子 Promise 和新的语法支持 async/await。这些比石器时代的 setTimeoutsetInterval 更受欢迎,因为您可以轻松地将数据线程化通过异步控制流,停止考虑“回调”,并避免副作用 -

      class Algorithm {
        constructor() {
          ...
          this.runProcess(...)
        }
        async runProcess(...) { // async
          while (true) {        // loop instead of recursion
            await sleep(...)    // sleep some amount of time
            this.someFunction() // do work
            ...                 // adjust timer variables
          }
        }
      }
      

      sleep 是一个简单的函数,它在指定的毫秒值 ms 之后解析一个承诺 -

      function sleep(ms) {
        return new Promise(r => setTimeout(r, ms)) // promise
      }
      

      异步迭代

      但是看看this.someFunction() 怎么没有返回任何东西?如果我们能从someFunction 捕获数据并将其提供给我们的调用者,那就太好了。通过将runProcess 设为async generator 并实现Symbol.asyncIterator,我们可以轻松处理异步停止副作用-

      class Algorithm {
        constructor() {
          ...
          this.data = this.runProcess(...)  // assign this.data
        }
        async *runProcess(...) {            // async generator
          while (true) {
            await sleep(...)    
            yield this.someFunction()       // yield
            ...
          }
        }
        [Symbol.asyncIterator]() {          // iterator
          return this.data
        }
      }
      

      现在调用者可以控制从this.someFunction 传入数据时发生的情况。下面我们写信给console.log,但您可以轻松地将其替换为 API 调用或写入文件系统 -

      const foo = new Algorithm(...)
      for await (const data of foo)
        console.log("process data", data) // or API call, or write to file system, etc
      

      附加控制

      您可以通过使用其他数据成员轻松添加对流程的控制。下面我们用条件替换while(true),并允许调用者停止进程-

      class Algorithm {
        constructor() {
          ...
        }
        async *runProcess(...) {
          this.running = true       // start
          while (this.running) {    // conditional loop
            ...
          }
        }
        haltProcess() {
          this.running = false      // stop
        }
        ...
      }
      

      演示

      这是一个包含上述概念的功能演示。注意我们在这里只实现halt 因为run 是一个infinite 生成器。有限生成器不需要手动停止。通过运行 sn -p 在您自己的浏览器中验证结果 -

      class Algorithm {
        async *run() {
          this.running = true
          while(this.running) {
            await sleep(1000)
            yield this.someFunction()
          }
        }
        halt() {
          this.running = false
        }
        someFunction() {
          return Math.random()
        }
        [Symbol.asyncIterator] = this.run
      }
      
      function sleep(ms) {
        return new Promise(r => setTimeout(r, ms))
      }
      
      async function main() {
        const foo = new Algorithm          // init
        setTimeout(_ => foo.halt(), 10000) // stop at some point, for demo
        for await (const x of foo)         // iterate
          console.log("data", x)           // log, api call, write fs, etc
        return "done"                      // return something when done
      }
      
      main().then(console.log, console.error) // "done"
      data 0.3953947360028206
      data 0.18754462176783115
      data 0.23690422070864803
      data 0.11237466374294014
      data 0.5123244720637253
      data 0.39818889343799635
      data 0.08627407687877853
      data 0.3861902404922477
      data 0.8358471443658225
      data 0.2770336562516085
      done
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-09
        • 2021-07-11
        • 2010-11-04
        • 2012-10-31
        • 2012-08-31
        • 1970-01-01
        • 2011-02-28
        相关资源
        最近更新 更多