如何修复或解决 fetch 中的内存泄漏问题?

问题描述 投票:0回答:1

类似于这个问题: Fetch API 在 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 Heap 中。我必须使用任务管理器才能看到它。
  • 有时,主动轮询时内存会被清除,但不可避免地会达到极端水平。
  • Edge 也显示了这个问题,但似乎更主动地清除内存。尽管它最终仍会增加 1GB+ 的额外内存使用量。

我做错了什么,还是这是一个错误?关于如何让这种轮询长期工作而不出现内存泄漏有什么想法吗?

javascript google-chrome memory-leaks fetch-api
1个回答
1
投票

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

如果我使用此执行顺序启动此处的代码片段,则 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();
    })
}()

© www.soinside.com 2019 - 2024. All rights reserved.