【问题标题】:Huge Memory Leaks with XMLHttp POST RequestXMLHttp POST 请求导致大量内存泄漏
【发布时间】:2016-09-02 05:51:38
【问题描述】:

如何避免 XHR POST 内存泄漏?我浏览了很多关于 XHR 内存泄漏的网页,但没有好的解决方案。我的问题几乎与this 类似,该博客解释了问题但没有解决方案。

我的问题: 我有一个网络应用程序,它不断向服务器发送日期(2Mb 到 80Mb),它会发出 10 到 300 个请求。这是 POST 请求。对于 GET 请求,这样的问题不大。

我该如何解决这个问题? 循环参考,范围,更接近等我尝试但没有成功。 我尝试使用 delete 关键字进行就绪状态更改,删除以前的 xhr 对象,尝试重用 xhr,xhr 对 null 的引用,更改编码模式等

这是示例代码。这是我需要的功能

 var base_string =  "ABCDEFGHIJKLMNOPQUST01234567890!@#$%^&:ABCDEFGHIJKLMNOPQUST01234567890!@#$%^&ABCDEFGHIJKLMNOPQUST01234567890!@#$%^&";
            base_string += base_string;  
            base_string += base_string; 
            base_string += base_string; 
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string; 
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string; 
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string;  
            base_string += base_string;  
            this.sampleData = base_string;
            var dataToSend = this.sampleData.substring( 0, 2000000 );



           this.xhr = [];
           this.xhr[0] = new XMLHttpRequest();
           function sendRequest (){
               var Self = this;
               Self.xhr[0].onload = function (test) {
                   sendRequest ();
               };

               Self.xhr[0].open("POST", "http://localhost/upload.php" + "?n=" +  Math.random(), true);
               Self.xhr[0].send(dataToSend);
           }
           sendRequest ();

我怎样才能在没有内存泄漏的情况下做到这一点?

【问题讨论】:

  • 我看不出你想用那个看起来很奇怪的 sendRequest 函数来实现什么 - 从来没有见过有人这样做 - 你认为它的目的是什么? - 或者数组,只有一个元素……都是奇怪的代码,看起来像是为了引起问题而设计的
  • 目的是测量连接的上传速度
  • 好吧,它不会做这样的事情 - 不确定它是否会导致错误或继续重复发送数据......哦,我明白了,它应该发送然后完成后发送再次,无限
  • 我也试试 if(Self.xhr.readyState == 4 && Self.xhr.status == 200){} 没有变化!
  • 所以这个函数会在前一个请求完成后重复发送一个大的 POST 请求......你想知道内存泄漏在哪里......

标签: javascript ajax memory-leaks


【解决方案1】:

清理你的代码 - 这应该做同样的事情,而不需要奇怪和毫无意义地使用 Self 和数组......它还会重新初始化 xhr

我已更改为上传加载事件添加一个侦听器 - 这里的快速测试似乎没有泄漏(似乎)

// snip
this.sampleData = base_string;
var dataToSend = this.sampleData.substring( 0, 2000000 );

function sendRequest (){
    var xhr = new XMLHttpRequest();
    xhr.upload.addEventListener('load', function (e) {
        sendRequest ();
    });

    xhr.open("POST", "http://localhost/upload.php" + "?n=" +  Math.random(), true);
    xhr.send(dataToSend);
}
sendRequest ();

【讨论】:

  • 关闭 google chrome 或 firefox 的 Javascript 控制台以更快地执行此脚本 .. 并在您的任务管理器中查看内存的增长
  • EventListener 没有为我触发
  • 你用的是什么浏览器?
  • 对不起,我在 WebWroker 设置上测试这个。现在我在正常设置下对其进行了测试! EventListener 正在触发!但是巨大的泄漏仍然存在:(
  • 哇,firefox 显示了与原始代码相比可能存在微小漏洞 - 很难说,因为 firefox 无论如何都充满了漏洞
【解决方案2】:

连续 + 请求的大小 + 请求的数量。我认为你不应该在这种情况下使用 XHR。也许是 WebRTC、长轮询或 Web 套接字。即使您找到一种解决方法来以这种方式执行它,这也不会扩展。

【讨论】:

    【解决方案3】:

    对于您发送的每个请求,您都会添加一个新的 onload 处理程序。

    Self.xhr[0].onload = function (test) {
        sendRequest ();
    };
    

    此时旧的处理程序不会被删除并保留在内存中。垃圾收集器将无法释放内存。

    在您的情况下,您只需要一个事件监听器,所以我建议像这样将监听器的附件移出 sendRequest 函数,并且内存泄漏应该消失了。

    this.xhr = [];
    this.xhr[0] = new XMLHttpRequest();
    xhr[0].onload = function (test) {
        sendRequest ();
    };
    function sendRequest (){
        xhr[0].open("POST", "http://localhost/upload.php" + "?n=" +  Math.random(), true);
        xhr[0].send(dataToSend);
    }
    sendRequest (); 
    

    编辑:版本 2

    我尝试了另一个版本,它产生了更好的结果。在我的设置中,内存从未超过 2.6G。它是 Jaromandas 作品的衍生作品。 基本上是他的版本加上removeEventHandlerdelete

    function sendRequest (){
    function run(e){
      xhr.upload.removeEventListener('load',run)
      sendRequest()
    }
    var xhr = new XMLHttpRequest();
    xhr.upload.addEventListener('load', run);
    xhr.open("POST", "http://localhost:2345/" + "?n=" +  Math.random(), true);
    xhr.send(dataToSend);
    delete xhr
    }
    sendRequest ();
    

    【讨论】:

    • 这很奇怪,对我来说它运行良好(Linux、Chrome、Node.js 服务器,都在一台机器上)Chrome 的内存使用量上升到大约 4G,然后垃圾收集开始,它下降到大约2G 涨回 4G 又跌落……一直在波动,永远不会超过 4G。
    • 对不起,我在 Safari 上测试过!它仍然在做同样的事情!刚刚看了 10GB+ 内存使用 :)。昨天我正在尝试不同的方法来解决这个问题。一些解决方案的行为是这样的。 Firefox 从 900Mb 降到 400Mb! Chrome 达到 2.34Gb 并下降到 1.8Gb 等,但我认为这仍然是一个巨大的泄漏!因为一个 Dead 简单的 Ajax 发布请求需要这么多内存?所以我觉得我做错了什么!
    • 编辑:版本 2 这是更好的版本! Firefox 从 10GB 降到 600Mb! Chrome 的范围是 800 到 900!
    • 不幸的是 safari 仍然在做同样的事情!
    • removeEventListener 在 Windows 10 和 Mac 上运行良好(在两者上都测试了 Chrome、Firefox 和 Edge 在 Mac 上的 W10 Safari 上)只有 SAFARI 仍然继续表现得像我的原始代码一样其他一切都表现不同但更好! Mac 上的 Firefox 达到 10GB 并回到 600MB,W10 上的 Firefox 湿至 3.5 GB 并回到 200!你觉得野生动物园怎么样?我想我会忽略野生动物园!继续我的工作!
    【解决方案4】:

    尝试更新的现代方法,使用 fetch...?

    let url = '/upload.php'
    let myInit = {
        method: 'post',
        cache: 'no-store',
        body: new ArrayBuffer(2000000)
    }
    
    function sendRequest() {
        return fetch(url, myInit)
            .then(res => res.blob())
            .then(sendRequest)
    }
    
    sendRequest()
    

    【讨论】:

    • MDN 说这是一项实验性技术! IE等不支持。我也需要进度处理程序!
    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 2014-06-07
    相关资源
    最近更新 更多