`
xyh
  • 浏览: 86086 次
  • 性别: Icon_minigender_1
  • 来自: China
社区版块
存档分类
最新评论

Javascript Memory Leak

阅读更多

困扰

IE memory leaks like a sieve(筛子) and my webpage is getting slower and slo...ower. But memory usage keeps climbing… I've tried everything including banging my head on the desk(猛敲桌子). It just doesn't change anything.

IE的内存泄露使得网页速度变得越来越慢。然后这不要紧,浏览器占用的内存一直在上升,我尝试了各种方法,甚至猛拍桌子,但都无济于事。

 

解释

The fact is that IE has separate garbage collecting mechanisms for COM interfaces and JavaScript objects and is unable to resovle circular references between DOM(or ActiveX or any kind of COM) objects and JavaScript objects. (原因是IE分离了COM接口和JavaScript对象相互之间的垃圾回收,所以不能解决DOM对象和javascript对象之间的闭包问题)When objects form the two worlds have circular references between them, GC can not detect them and the memory cannot be reclaimed until IE exists.(当DOM对象和JavaScript对象有闭包引用的时候,由它们创建的对象,垃圾回收机制不能检测到它们,所以除非不用IE,对象所占的内存不能被回收) There are several patterns that cause circular references.(造成闭包的原因由好几种,一种误解就是将内部函数作为事件的响应函数会造成内存泄露。) Unfortunately, assigning nested functions as event handlers falls into this category. IE is rejecting the use of closure, one of the most powerful and flexible feature of JavaScript.

(闭包是Javascript的一个很有用,而且很灵活的特征,但是IE不会回收闭包的使用带来的内存)

牢骚

It is frustrating to know that experts at Microsoft like Eric Lippert suggest "Don't use closures unless you really need closure semantics. In most cases, non-nested functions are the right way to go." It sounds like that programmers are abusing closures, completely ignoring that IE has a big problem with closures. It would be reliefing and reasonable to expect that IE will relaim leaked memory after a page has been unloaded. But that's not the fact. And here I found some explanation: "...the application compatibility lab discovered that there were actually web pages that broke when those semantics were implemented. (No, I don't know the details.) The IE team considers breaking existing web pages that used to work to be way, way worse than leaking a little memory here and there, so they've decided to take the hit and leak the memory in this case." I don't understand. Maintaining backward compatibility with rare web pages which even an scripting engine writer does not know much about at the cost of leaking memory possibly for all web pages? What kind of decision is it? They don't admit their own faults but instead suggest poor coding practices.

测试

But we have to code for IE, however buggy it is. I've run the test from Mihai Bazon(see IE: WHERE'S MY MEMORY?).

 

js 代码
  1. function createEl(i) {   
  2.     var span = document.createElement("span");   
  3.     span.className = "muci";   
  4.     span.innerHTML = " foobar #"+i+" ";   
  5.     span.onclick = function() { alert(this.innerHTML + "n" + i); };   
  6.     document.body.appendChild(span);   
  7. }function start() {   
  8.     var T1 = (new Date()).getTime(); // DEBUG.PROFILE   
  9.     for (var i = 0; i < 3000; ++i)   
  10.         createEl(i);   
  11.     alert(((new Date()).getTime() - T1) / 1000); // DEBUG.PROFILE   
  12. }  

The first request in IE took 1.797s, the tenth 8.063s. Memory usage kept growing. Firefox reports a typical value of 1.6xs with no memory leak. Prototype.js avoids IE memory leak by hooking window's unload event, unobserving all events and clearing its event handler cache. I replaced the line span.onclick = function() { alert(this.innerHTML + "n" + i); }; with Event.observe(span, 'click', function() { alert(this.innerHTML + "n" + i); }); and rerun the test. The good news is that the leaked memory in IE is reclaimed when the page unloads. The bad news is that each request takes approximately 17s in IE while Firefox only needs 2.1xs! The Prototype event system makes it possible to free memory when page unloads but is extremely slow and uses more memory in a single request. The speed degradation is explainable: Event._observeAndCache saves extra references thus uses more memory and IE gets slow as it leaks memory. Event.observe does more things than a simple assignment thus is much slower. However, memory leak is under control…

思考

I admire Edward Dean's addEvent though it doesn't solve the memory leak problem with closures. (Dean insisted that his script does not leak memory in comments. Maybe he is not talking about the closure case). Leak Free Javascript Closures solution can really prevent memory leak. The way it breaks cirular reference is create a new function which holds no references to the closing scope.

In the simplest case:

 

js 代码
  1. //See update below   
  2. //Function.prototype.closure = function() {   
  3. //    return function () {   
  4. //        return this.apply(null, arguments);   
  5. //    };   
  6. //};//update 2006-08-22 13:10:15 GMT+0800   
  7. //Holds references to functions   
  8. __funcs = [];//The code fragment is for demostrative purpose only and lacks of optimization.   
  9. //Do not use it in productive enviromnent!   
  10. Function.prototype.closure = function() {   
  11.     __funcs.push(this);   
  12.     return function () {   
  13.     return __funcs[__funcs.length - 1].apply(null, arguments);   
  14.     };   
  15. };   
  16. function setup() {   
  17.     var span = $('span1');   
  18.     span.bigProperty = new Array(1000).join('-_-');   
  19.     span.onclick = function() {alert(span.bigProperty.length);}.closure();   
  20. }   
  21. setup();  

This will not leak memory in IE. The nested function in setup() forms a closure so it's able access span. span.onclick does not refer to the nested function but a newly created function returned by the closure() method of the nested function. The newly created function invokes the nested function via global array __funcs and have no references to the scope of setup(). So there is no circular reference. You may argue that the newly created function is able to call the nested function, it must have some kind of reference to it while the nested function have reference to span via closure, so there will be a circular reference. However, ECMA 262 treat this as a keyword rather than an identifier, this keyword is resolved dependent on execution context in which it occurs, without reference to the scope chain (see Javascript Closures ). It means that this keyword is free of reference so it can be cleverly used to break circular references. This is a hack indeed. IE always needs hacks to amend its holes.

分享到:
评论

相关推荐

    Memory Leak.zip

    JavaScript是一种广泛应用于Web开发的脚本语言,它在执行时占据内存资源,如果代码编写不当,可能会出现“内存泄漏”(Memory Leak)的问题。内存泄漏是程序运行时未释放不再使用的内存,导致系统资源浪费,严重时...

    Angularjs memory leak in ie8 test

    在前端开发中,AngularJS是一个非常流行的JavaScript框架,用于构建交互式和动态的Web应用。然而,由于AngularJS的设计特性,尤其是在旧版浏览器如Internet Explorer 8(IE8)中,可能会遇到内存泄漏的问题。这篇...

    memwatch_for_memory_leak_detect

    const arr = new Array(10000).fill(new Array(10000).fill('memory leak')); } ``` 在这个例子中,我们首先监听 `leak` 事件,当检测到内存泄漏时,会输出相关信息。然后定义了一个 `reportSnapshot` 函数,用于...

    createjs_memory_leak_in_chrome:createjs + chrome =内存泄漏

    createjs_memory_leak_in_chrome 演示: : 当canvas.style.display为none时,chrome中的内存泄漏使用chrome的任务管理器。 在chrome中,当canvas.style.display为none时,内存泄漏,请与Chrome的任务管理器联系。 ...

    quickjs-memory-leak

    该项目是通过引导的。 可用脚本 在项目目录中,可以运行: yarn start 在开发模式下运行应用程序。 打开在浏览器中查看它。 如果您进行编辑,则页面将重新加载。 您还将在控制台中看到任何棉绒错误。...

    JAVA看不了string源码-JavaScript-memory-leak-checker:MemoryLeakChecker可以检查Jav

    JAVA看不了字符串源码...源memory_leak_checker.js和来自JavaScript的调用: MemoryLeakChecker(window) 这将分析每个对象并列出并输出具有200多个元素的任何对象或列表。 这对于查找数据结构中的泄漏可能非常有用。

    taro-memory-leak-issue

    通过以上分析,我们可以看到,解决“taro-memory-leak-issue”需要对JavaScript内存管理和Taro框架有深入理解,同时结合有效的诊断工具和策略,才能确保应用的高效运行。在实际开发中,开发者应养成良好的编程习惯,...

    fs.readfile-memory-leak.jest

    执行测试用例 yarn test-gc错误如果将LEAKY依赖项之一注释到Leak.js中,则不再释放每个文件的内存。泄漏// const fs = require('fs-extra'); //TODO: LEAKY// const fs = require('graceful-fs'); //TODO: LEAKY// ...

    dns-memory-leak

    dns-内存泄漏测试存储库以重现和调试节点 dns 内存泄漏。问题当 DNS 失败或使用某些 DNS 记录(如 IP 列表)时,我们会注意到我们的生产...npm run watch-memory 假设当前只有一个node进程正在运行,您可以使用npm run

    在JavaScript中使用inline函数的问题

    前段时间被IE和JavaScript脚本引擎的Memory Leak问题弄得郁闷坏了,不过幸好现在总算是柳暗花明了,并且找到了一些IE中使用脚本避免ML问题的方法。继续研究JavaScript的编写,有发现一些不算ML问题,但是可以节约IE...

    javascript 内存泄漏

    JavaScript作为一门用于添加动态内容至网页的强大脚本语言,其易学易用性使其在创建动态菜单组件、密码验证等日常任务中非常有帮助。尽管JavaScript便于编写,但它在特定浏览器中容易出现内存泄漏的问题。本文将详细...

    JavaScript Applications with Node.js, React, React Native and MongoDB

    14.3. Memory Leak Detection 14.4CI/CD 14.5Monitoring and Alerting PARTIII: The Presentation Laver (React/HTML) Chapter 15: Fundamentals 15.1Defnition of the Presentation Layer 15.2Introducing React ...

    go-duktape:Go的Duktape JavaScript引擎绑定

    Go(Golang)的Duktape绑定 是一个薄的,可嵌入的javascript引擎。 大部分已实现。 例外在列出。 用法 该软件包是完全可获取的,无需安装任何外部C库。 因此,只需键入go get gopkg.in/... // To prevent memory leak

    内存分析工具 MemoryAnalyzer-1.8.1-win32.x86-64.zip

    8. **Leak Suspects报告**:MAT自动生成的Leak Suspects报告,通过算法分析出最有可能导致内存泄漏的嫌疑对象和链路。 为了充分利用MemoryAnalyzer 1.8.1,用户需要首先获取heap dump文件。这通常可以通过在Java...

    动态加载JavaScript文件的两种方法

    // Handle memory leak in IE script.onload = script.onreadystatechange = null; } }; script.src = 'helper.js'; head.appendChild(script); ``` 这种方法的一个优势是,如果`helper.js`文件的末尾包含了`...

    内存泄漏检测工具

    除了“IE Javascript leaks detector”,还有其他内存泄漏检测工具,例如`Drip-0.2.exe`(Drip Memory Leak Detector),这是一款适用于Node.js环境的内存泄漏检测工具。它能够帮助开发者监测Node.js应用程序的内存...

    JavaScript中内存泄漏的介绍与教程(推荐)

    本文主要给大家详细介绍了关于JavaScript中内存...不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。 有些语言(比如 C 语言)必须手动释放内存,程序员负责内存管理。 char * buffer; buffer = (char

    React-内存泄露常见问题解决方案.docx

    不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。 JavaScript 中常见的几种内存泄露 ----------------------------- ### 全局变量引起的内存泄露 在 JavaScript 中,变量的作用域是函数范围的。...

    浅谈VueJS SSR 后端绘制内存泄漏的相关解决经验

    Memory Leak 是最难排查调试的 Bug 种类之一,因为内存泄漏是个 undecidable problem,只有开发者才能明确一块内存是不是需要被回收。再加上内存泄漏也没有特定的报错信息,只能通过一定时间段的日志来判断是否存在...

    leetcode分类-blog::cookie:我的博客

    对于不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak) 四种常见的内存泄露 意外的全局变量 未声明的变量 使用this创建的变量 被遗忘的计时器或回调函数 定时器引起 观察者addEventListener 脱离DOM的...

Global site tag (gtag.js) - Google Analytics