【问题标题】:How do I fix or work around this memory leak in fetch?如何在 fetch 中修复或解决此内存泄漏?
【发布时间】:2021-12-24 04:34:19
【问题描述】:

类似于这个问题: Fetch API leaks memory in Chrome

当使用 fetch 定期轮询数据时,Chrome 的内存使用量会不断增加而不会释放内存,最终导致崩溃。

https://jsfiddle.net/abfinz/ahc65y3s/13/

const state = {
    response: {},
  count: 0
}

function poll(){
    fetch('https://upload.wikimedia.org/wikipedia/commons/3/3d/LARGE_elevation.jpg')
    .then(response => {
      state.response = response;
      state.count = state.count + 1;
      if (state.count < 20){
        console.log(state.count);
                setTimeout(poll, 3000);
      } else {
        console.log("Will restart in 1 minute");
        state.count = 0;
        setTimeout(poll, 60000);
      }
    });
}

poll();

这个 JSFiddle 很好地展示了这个问题。通过每 3 秒轮询一次数据,似乎有什么东西导致 Chrome 不断地占用内存。如果我让它停止并等待几分钟,它通常会释放内存,但如果轮询继续,它通常会保留它。此外,如果我让它运行几个完整的周期,即使从开发工具的性能选项卡中强制进行垃圾收集也不会总是释放所有内存。

  • 内存未显示在 JS 堆中。我必须使用任务管理器才能看到它。
  • 有时,内存会在主动轮询时清除,但不可避免地会累积到极端水平。
  • Edge 也显示了该问题,但似乎更主动地清除了内存。尽管它最终仍会增加 1GB 以上的额外内存使用量。

是我做错了什么,还是这是一个错误?关于如何让这种轮询在没有内存泄漏的情况下长期工作的任何想法?

【问题讨论】:

  • 不确定是否与问题有关,但是如果您使用.then()来处理响应,为什么还要使用await
  • 垃圾收集并不总是将内存返回给操作系统。堆碎片通常可以防止这种情况发生。
  • 您只是以该图像为例,还是每次都尝试获取相同的图像?
  • @Barmar 是的,这是原始代码和测试代码不同的产物。对不起。
  • @PeteKuhlmann 你可能应该使用网络套接字,而不是不断的请求。 socket.io

标签: javascript google-chrome memory-leaks fetch fetch-api


【解决方案1】:

我玩了一下,它似乎是响应处理的一个错误,因此如果您不调用任何响应函数,它就不会释放分配的内存。

如果我使用此执行顺序在此处启动代码 sn-p,chrome 任务管理器和 windows 任务管理器会不断报告相同的大小 30 MB。同时它也在 jsfiddle 上运行,请求 #120 有 30 MB。

const state = {
    response: {},
    count: 0
  },
  uri = 'https://upload.wikimedia.org/wikipedia/commons/3/3d/LARGE_elevation.jpg';

!function poll() {
  const controller = new AbortController(),
    signal = controller.signal;
  // using this you can cancel it and destroy it completly.
  fetch(uri, { signal })
    // this is triggered as soon as the header data is transfered
    .then(response => {
      /**
       * Continung without doing anything on response
       * fills the memory.
       *
       * Chrome downloads the file in the background and 
       * seems to wait for the use of a call on the
       * response.fx() or an abort signal.
       * 
       * This seems to be a bug or a small design mistake
       * if response is never used.
       *
       * If response.json(), .blob(), .body() or .text() is
       * called the memory will be free'd.
       */
      return response.blob();
    }).then((binary) => {
      // store data to a var
      return state.response = binary;
    }).catch((err) => {
      console.error(err);
    }).finally(() => {
      // and start the next poll
      console.log(++state.count, state.response.type, (state.response.size / 1024 / 1024).toFixed(2)+' MB');
      requestAnimationFrame(poll);
      // console.dir(state.response);
      
      // reduces memory a bit more
      controller.abort();
    })
}()

【讨论】:

  • 当我在 JSFiddle 中运行它时,Chrome 任务管理器报告内存使用情况一致,但 Windows 任务管理器显示持续增长,几分钟后超过 3 GB,Chrome 很快就会崩溃。
  • 我对@9​​87654322@ 进行了同样的尝试,它使用了 XMLHttpRequest,但提供了 fetch() 的基本功能。使用这个系统任务管理器内的内存保持低。 - 您是否在 bugs.chromium.org/p/chromium 上报告了此行为?
  • 感谢您的链接。我没有举报,但我只是举报了。
  • 此错误似乎已在下一个Updates 中修复。
猜你喜欢
  • 2020-04-07
  • 1970-01-01
  • 2020-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
相关资源
最近更新 更多