Js内存泄漏及解决方案

合集下载

js内存泄漏场景、如何监控及分析详解

js内存泄漏场景、如何监控及分析详解

js内存泄漏场景、如何监控及分析详解⽬录前⾔哪些情况会引起内存泄漏1. 意外的全局变量2. 遗忘的定时器3. 使⽤不当的闭包4. 遗漏的 DOM 元素5. ⽹络回调如何监控内存泄漏如何分析内存泄漏,找出有问题的代码实例分析总结前⾔Q:什么是内存泄漏?字⾯上的意思,申请的内存没有及时回收掉,被泄漏了Q:为什么会发⽣内存泄漏?虽然前端有垃圾回收机制,但当某块⽆⽤的内存,却⽆法被垃圾回收机制认为是垃圾时,也就发⽣内存泄漏了⽽垃圾回收机制通常是使⽤标志清除策略,简单说,也就是引⽤从根节点开始是否可达来判定是否是垃圾上⾯是发⽣内存泄漏的根本原因,直接原因则是,当不同⽣命周期的两个东西相互通信时,⼀⽅⽣命到期该回收了,却被另⼀⽅还持有时,也就发⽣内存泄漏了所以,下⾯就来讲讲,哪些场景会造成内存泄漏哪些情况会引起内存泄漏1. 意外的全局变量全局变量的⽣命周期最长,直到页⾯关闭前,它都存活着,所以全局变量上的内存⼀直都不会被回收当全局变量使⽤不当,没有及时回收(⼿动赋值 null),或者拼写错误等将某个变量挂载到全局变量时,也就发⽣内存泄漏了2. 遗忘的定时器setTimeout 和 setInterval 是由浏览器专门线程来维护它的⽣命周期,所以当在某个页⾯使⽤了定时器,当该页⾯销毁时,没有⼿动去释放清理这些定时器的话,那么这些定时器还是存活着的也就是说,定时器的⽣命周期并不挂靠在页⾯上,所以当在当前页⾯的 js ⾥通过定时器注册了某个回调函数,⽽该回调函数内⼜持有当前页⾯某个变量或某些 DOM 元素时,就会导致即使页⾯销毁了,由于定时器持有该页⾯部分引⽤⽽造成页⾯⽆法正常被回收,从⽽导致内存泄漏了如果此时再次打开同个页⾯,内存中其实是有双份页⾯数据的,如果多次关闭、打开,那么内存泄漏会越来越严重⽽且这种场景很容易出现,因为使⽤定时器的⼈很容易遗忘清除3. 使⽤不当的闭包函数本⾝会持有它定义时所在的词法环境的引⽤,但通常情况下,使⽤完函数后,该函数所申请的内存都会被回收了但当函数内再返回⼀个函数时,由于返回的函数持有外部函数的词法环境,⽽返回的函数⼜被其他⽣命周期东西所持有,导致外部函数虽然执⾏完了,但内存却⽆法被回收所以,返回的函数,它的⽣命周期应尽量不宜过长,⽅便该闭包能够及时被回收正常来说,闭包并不是内存泄漏,因为这种持有外部函数词法环境本就是闭包的特性,就是为了让这块内存不被回收,因为可能在未来还需要⽤到,但这⽆疑会造成内存的消耗,所以,不宜烂⽤就是了4. 遗漏的 DOM 元素DOM 元素的⽣命周期正常是取决于是否挂载在 DOM 树上,当从 DOM 树上移除时,也就可以被销毁回收了但如果某个 DOM 元素,在 js 中也持有它的引⽤时,那么它的⽣命周期就由 js 和是否在 DOM 树上两者决定了,记得移除时,两个地⽅都需要去清理才能正常回收它5. ⽹络回调某些场景中,在某个页⾯发起⽹络请求,并注册⼀个回调,且回调函数内持有该页⾯某些内容,那么,当该页⾯销毁时,应该注销⽹络的回调,否则,因为⽹络持有页⾯部分内容,也会导致页⾯部分内容⽆法被回收如何监控内存泄漏内存泄漏是可以分成两类的,⼀种是⽐较严重的,泄漏的就⼀直回收不回来了,另⼀种严重程度稍微轻点,就是没有及时清理导致的内存泄漏,⼀段时间后还是可以被清理掉不管哪⼀种,利⽤开发者⼯具抓到的内存图,应该都会看到⼀段时间内,内存占⽤不断的直线式下降,这是因为不断发⽣GC,也就是垃圾回收导致的针对第⼀种⽐较严重的,会发现,内存图⾥即使不断发⽣ GC 后,所使⽤的内存总量仍旧在不断增长另外,内存不⾜会造成不断 GC,⽽ GC 时是会阻塞主线程的,所以会影响到页⾯性能,造成卡顿,所以内存泄漏问题还是需要关注的我们假设这么⼀种场景,然后来⽤开发者⼯具查看下内存泄漏:场景⼀:在某个函数内申请⼀块内存,然后该函数在短时间内不断被调⽤// 点击按钮,就执⾏⼀次函数,申请⼀块内存startBtn.addEventListener("click", function() {var a = new Array(100000).fill(1);var b = new Array(20000).fill(1);});⼀个页⾯能够使⽤的内存是有限的,当内存不⾜时,就会触发垃圾回收机制去回收没⽤的内存⽽在函数内部使⽤的变量都是局部变量,函数执⾏完毕,这块内存就没⽤可以被回收了所以当我们短时间内不断调⽤该函数时,可以发现,函数执⾏时,发现内存不⾜,垃圾回收机制⼯作,回收上⼀个函数申请的内存,因为上个函数已经执⾏结束了,内存⽆⽤可被回收了所以图中呈现内存使⽤量的图表就是⼀条横线过去,中间出现多处竖线,其实就是表⽰内存清空,再申请,清空再申请,每个竖线的位置就是垃圾回收机制⼯作以及函数执⾏⼜申请的时机场景⼆:在某个函数内申请⼀块内存,然后该函数在短时间内不断被调⽤,但每次申请的内存,有⼀部分被外部持有// 点击按钮,就执⾏⼀次函数,申请⼀块内存var arr = [];startBtn.addEventListener("click", function() {var a = new Array(100000).fill(1);var b = new Array(20000).fill(1);arr.push(b);});看⼀下跟第⼀张图⽚有什么区别?不再是⼀条横线了吧,⽽且横线中的每个竖线的底部也不是同⼀⽔平了吧其实这就是内存泄漏了我们在函数内申请了两个数组内存,但其中有个数组却被外部持有,那么,即使每次函数执⾏完,这部分被外部持有的数组内存也依旧回收不了,所以每次只能回收⼀部分内存这样⼀来,当函数调⽤次数增多时,没法回收的内存就越多,内存泄漏的也就越多,导致内存使⽤量⼀直在增长另外,也可以使⽤ performance monitor ⼯具,在开发者⼯具⾥找到更多的按钮,在⾥⾯打开此功能⾯板,这是⼀个可以实时监控 cpu,内存等使⽤情况的⼯具,会⽐上⾯只能抓取⼀段时间内⼯具更直观⼀点:梯状上升的就是发⽣内存泄漏了,每次函数调⽤,总有⼀部分数据被外部持有导致⽆法回收,⽽后⾯平滑状的则是每次使⽤完都可以正常被回收这张图需要注意下,第⼀个红框末尾有个直线式下滑,这是因为,我修改了代码,把外部持有函数内申请的数组那⾏代码去掉,然后刷新页⾯,⼿动点击 GC 才触发的效果,否则,⽆论你怎么点 GC,有部分内存⼀直⽆法回收,是达不到这样的效果图的以上,是监控是否发⽣内存泄漏的⼀些⼯具,但下⼀步才是关键,既然发现内存泄漏,那该如何定位呢?如何知道,是哪部分数据没被回收导致的泄漏呢?如何分析内存泄漏,找出有问题的代码分析内存泄漏的原因,还是需要借助开发者⼯具的 Memory 功能,这个功能可以抓取内存快照,也可以抓取⼀段时间内,内存分配的情况,还可以抓取⼀段时间内触发内存分配的各函数情况利⽤这些⼯具,我们可以分析出,某个时刻是由于哪个函数操作导致了内存分配,分析出⼤量重复且没有被回收的对象是什么这样⼀来,有嫌疑的函数也知道了,有嫌疑的对象也知道了,再去代码中分析下,这个函数⾥的这个对象到底是不是就是内存泄漏的元凶,搞定先举个简单例⼦,再举个实际内存泄漏的例⼦:场景⼀:在某个函数内申请⼀块内存,然后该函数在短时间内不断被调⽤,但每次申请的内存,有⼀部分被外部持有// 每次点击按钮,就有⼀部分内存⽆法回收,因为被外部 arr 持有了var arr = [];startBtn.addEventListener("click", function() {var a = new Array(100000).fill(1);var b = new Array(20000).fill(1);arr.push(b);});内存快照可以抓取两份快照,两份快照中间进⾏内存泄漏操作,最后再⽐对两份快照的区别,查看增加的对象是什么,回收的对象⼜是哪些,如上图。

常见的内存泄漏以及解决方案

常见的内存泄漏以及解决方案

常见的内存泄漏以及解决⽅案⼀、什么是内存泄漏? 系统进程不再⽤到的内存,没有及时的释放,就叫做内存泄漏。

⼆、JS引起内存泄漏的原因?1、意外的全局变量 由于js对没有进⾏申明的变量会默认是在全局变量上定义的,⽽系统的全局变量是 window,只有关闭窗⼝和刷新页⾯,全局变量才会被释放,如果在⼀个没有声明的变量上保存了⼤量的数据,这些数据就会保存在全局变量上,当这些数据没有及时的被回收,就会发⽣内存泄漏。

没有声明的变量function fn(){a='hello'}fn();使⽤this申明的变量function fn(){// 这⾥的this指向它的调⽤者,他的调⽤者是windowthis.a='hello';}fn() 解决⽅法: 避免使⽤没有声明的变量; 使⽤严格模式,在js⽂件头部或者是函数⾸⾏使⽤严格模式2、闭包引⽤的内存泄漏 由于闭包可以访问函数内部的变量,让这些变量⼀直保存在内存中,如果没有及时的清理掉这些变量,就会发⽣内存泄漏。

function fn(){var a='i am a';return function(){console.log(a);}} 解决⽅法:将事件处理程序定义在函数的外部// badfor(var k=0;k<10;k++){var t=function(a){console.log(a)}t(k)}// goodfunction t(a){console.log(a)}for(var k=0;k<10;k++){t(k)}t=null3、Dom元素的引⽤没有被释放 虽然在别的地⽅Dom别删除了,但是对象对这个Dom元素的引⽤并没有被删除var element={btn:document.getElementById('btn')}function doSomeThing(){element.btn.cilck()}function removeClick(){// 虽然移除了dom中的btn元素,但是对象中对btn的引⽤还是没有被删除document.body.removeChild(document.getElementById( 'btn' )) 解决⽅法:将element.btn=null4、被遗忘的定时器或者回调函数 定时器中有dom的引⽤,即使dom删除了,但是定时器还在,所以内存中还是会有这个dom。

JS闭包(内存溢出与内存泄漏)(垃圾回收机制)

JS闭包(内存溢出与内存泄漏)(垃圾回收机制)

JS闭包(内存溢出与内存泄漏)(垃圾回收机制)1.有关闭包定义闭包是指有权访问另⼀个函数作⽤域中变量的函数,创建闭包的最常见的⽅式就是在⼀个函数内创建另⼀个函数,通过另⼀个函数访问这个函数的局部变量闭包的特性:函数内再嵌套函数内部函数可以引⽤外层的参数和变量参数和变量不会被垃圾回收机制回收说说你对闭包的理解使⽤闭包主要是为了设计私有的⽅法和变量。

闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增⼤内存使⽤量,使⽤不当很容易造成内存泄露。

在js中,函数即闭包,只有函数才会产⽣作⽤域的概念闭包的最⼤⽤处有两个,⼀个是可以读取函数内部的变量,另⼀个就是让这些变量始终保持在内存中闭包的另⼀个⽤处,是封装对象的私有属性和私有⽅法好处:能够实现封装和缓存等;坏处:就是消耗内存、不正当使⽤会造成内存溢出的问题使⽤闭包的注意点由于闭包会使得函数中的变量都被保存在内存中,内存消耗很⼤,所以不能滥⽤闭包,否则会造成⽹页的性能问题,在IE中可能导致内存泄露解决⽅法是,在退出函数之前,将不使⽤的局部变量全部删除闭包的定义其实很简单:函数 A 内部有⼀个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包function A() {let a = 1window.B = function () {console.log(a)}}A()B() // 1闭包会产⽣⼀个很经典的问题:多个⼦函数的[[scope]]都是同时指向⽗级,是完全共享的。

因此当⽗级的变量对象被修改时,所有⼦函数都受到影响。

解决:变量可以通过函数参数的形式传⼊,避免使⽤默认的[[scope]]向上查找使⽤setTimeout包裹,通过第三个参数传⼊使⽤块级作⽤域,让变量成为⾃⼰上下⽂的属性,避免共享2.闭包简单例⼦指的是有权访问另⼀个函数作⽤域中变量的函数,创建闭包的常见⽅式,就是在⼀个函数内部创建另⼀个函数。

 function f1(){ var n=999; function f2(){ alert(n); // 999 } }function f1(){ var n=999; function f2(){ alert(n); } return f2; } var result=f1(); result(); // 9993.闭包的⽤处:闭包可以⽤在许多地⽅。

vue react 内存泄漏 处理方法

vue react 内存泄漏 处理方法

Vue & React 内存泄漏处理方法内存泄漏是在应用程序中常见的问题之一,当内存中的对象无法被垃圾回收器正确释放时,就会发生内存泄漏。

Vue和React作为两个流行的JavaScript框架,也不免会遇到内存泄漏的问题。

本文将详细介绍Vue和React中内存泄漏的原因,并提供一些常见的处理方法。

内存泄漏的原因1. 事件监听器未正确移除在Vue和React中,通常会使用addEventListener或类似的方法来添加事件监听器。

如果在组件销毁之前没有正确移除这些事件监听器,就会导致内存泄漏。

解决方法:在Vue中,可以使用beforeDestroy钩子函数来确保在组件销毁之前移除事件监听器。

示例代码如下:export default {beforeDestroy() {window.removeEventListener('resize', this.handleResize);},methods: {handleResize() {// 处理窗口大小变化事件}}}在React中,可以使用componentWillUnmount生命周期方法来移除事件监听器。

示例代码如下:class MyComponent extends ponent {componentWillUnmount() {window.removeEventListener('resize', this.handleResize);}handleResize() {// 处理窗口大小变化事件}render() {return <div>My Component</div>;}2. 定时器未正确清除在Vue和React中,使用setTimeout或setInterval等定时器函数时,如果没有正确清除定时器,就会导致内存泄漏。

解决方法:在Vue中,可以使用beforeDestroy钩子函数来确保在组件销毁之前清除定时器。

Js内存泄露问题总结

Js内存泄露问题总结

Js内存泄露问题总结最近接受了⼀个Js职位的⾯试,问了很多Js的⾼级特性,才发现长时间使⽤已知的特性进⾏开发⽽忽略了对这门语⾔循序渐进的理解,包括Java我想也是⼀样,偶尔在Sun官⽅看到JDK6.0列举出来的new features才发现很多东西是⾃⼰并不知道或者遗忘了的。

看来还是要坚持总结技术,反复理解和运⽤才能保持对任何技术的掌握运⽤能⼒阿。

翻了⼀些Js的新⽼资料,准备先讲讲Js的内存泄露问题——当⼀个DOM对象包含⼀个Js对象的引⽤(例如⼀个Event Handler),⽽这个Js对象⼜持有对这个DOM对象的引⽤时,⼀个环状引⽤就⾏成了。

这本⾝并不是什么错误或者Bug,因为Js的回收机制能理解这种环状的引⽤结构并且在没有其他对象能关联到环上的时候回收这个环上的所有对象内存。

可不幸的是IE浏览器中的DOM结构并不受Js解释机制管理,所以它并不能理解这种失去外界引⽤的环状结构,导致环上任何对象都⽆法被访问到,可是内存依旧占据着,这也就是所谓的Js内存泄露了。

我们来看⼀个经典的例⼦说明问题——JScript code(function(limit, delay){var queue=new Array(10);var n;function makeSpan(n){var s=document.createElement(‘span’);document.body.appendChild(s);var t=document.createTextNode(‘ ’+n);s.appendChild(t);s.onclick=function(e){s.style.backgroundColor=’red’;alert(n);};return s;}function process(n){queue.push(makeSpan(n));var s=queue.shift();if(s)s.parentNode.removeChild(s);}function loop()}{if(n<limit){process(n);n+=1;setTimeout(loop,delay);}}loop();})(10000,10);这个例⼦的意义是创建出10000个span元素来添加到DOM的body上,并且对其内容填充序号n,紧接着从queue的第⼀个位置移除创建的span元素,也就是说10000个为⽌,不断的创建再移除,永远只保留最新创建的那10个。

vue内存泄漏 阈值

vue内存泄漏 阈值

vue内存泄漏阈值Vue.js 作为一个前端框架,通常不会导致内存泄漏,除非你在使用它的时候不当地处理数据或事件。

内存泄漏通常发生在长时间运行的应用程序中,其中未释放的对象占用了越来越多的内存,最终导致应用程序崩溃或性能下降。

要确定Vue.js 应用程序是否存在内存泄漏,并为其设置阈值,你可以使用浏览器开发者工具中的性能(Performance)或内存(Memory)选项卡。

以下是一些步骤和建议,帮助你诊断和设置内存泄漏阈值:1. 使用浏览器开发者工具:打开你的Vue.js 应用程序。

右键点击页面,选择“检查”或使用快捷键(通常是F12 或Cmd+Opt+I)。

转到“性能”或“内存”选项卡。

2. 记录内存使用情况:在“性能”选项卡中,你可以开始记录并查看内存分配随时间的变化。

在“内存”选项卡中,你可以获取堆快照并比较它们以查看哪些对象未被垃圾回收。

3. 识别内存泄漏:查找内存使用量持续增长的区域。

检查是否有未被释放的大型对象或闭包。

查找不断增长的数据结构,如数组或对象。

4. 设置内存泄漏阈值:实际上,浏览器并没有直接提供一个设置内存泄漏阈值的选项。

阈值更多的是基于你的应用程序的特定需求和预期的内存使用情况。

你可以通过监控内存使用情况,并基于历史数据和预期行为设置一个“警告”阈值。

例如,如果你发现内存使用量在特定操作后持续上升超过50MB,这可能是一个警告信号。

5. 解决内存泄漏:确保你正确地解除了事件监听器。

避免在组件中存储大量不必要的数据。

使用Vue 的`v-if` 而不是`v-show` 来完全销毁和重建组件(如果适用)。

在不需要时清理定时器和异步操作。

考虑使用WeakMap 或WeakSet 来存储对DOM 节点的引用,这样当DOM 节点被垃圾回收时,引用也会自动被清除。

总之,诊断Vue.js 中的内存泄漏需要一定的经验和工具知识。

通过浏览器开发者工具,你可以监视内存使用情况并采取相应的措施来解决问题。

GC与JS内存泄露

GC与JS内存泄露

GC与JS内存泄露Javascript有没有内存泄露?如果有,如何避免?鉴于最近有好几个人问到我类似的问题,看来大家对这部分内容还没有系统的研究过,因此,打算在这里把个人几年前整理的一些资料和大家分享一下。

首先,可以肯定的说,javascript的一些写法会造成内存泄露的,至少在IE6下如此。

因此,在IE6迟迟不肯退休的今天,我们还是有必要了解相关的知识(虽然大部分情况下,js造成的这点内存泄露不是致使电脑运行变慢的主要原因)。

相关的研究主要集中在05-07这几年,本文并没有什么新的观点,如果当年有研究过的朋友,可以直接忽略。

作为前端开发人员,了解这些问题的时候,需要知其然也知其所以然,因此,在介绍js 内存泄露前,我们先从为什么会有内存泄露谈起。

说道内存泄露,就不得不谈到内存分配的方式。

内存分配有三种方式,分别是:一、静态分配( Static Allocation ):静态变量和全局变量的分配形式。

如果把房间看做一个程序,我们可以把静态分配的内存当成是房间里的耐用家具。

通常,它们无需释放和回收,因为没人会天天把大衣柜当作垃圾扔到窗外。

二、自动分配( Automatic Allocation ):在栈中为局部变量分配内存的方法。

栈中的内存可以随着代码块退出时的出栈操作被自动释放。

这类似于到房间中办事的人,事情一旦完成,就会自己离开,而他们所占用的空间,也随着这些人的离开而自动释放了。

三、动态分配( Dynamic Allocation ):在堆中动态分配内存空间以存储数据的方式。

也就是程序运行时用malloc或new申请的内存,我们需要自己用free或delete释放。

动态内存的生存期由程序员自己决定。

一旦忘记释放,势必造成内存泄露。

这种情况下,堆中的内存块好像我们日常使用的餐巾纸,用过了就得扔到垃圾箱里,否则屋内就会满地狼藉。

因此,懒人们做梦都想有一台家用机器人跟在身边打扫卫生。

在软件开发中,如果你懒得释放内存,那么你也需要一台类似的机器人——这其实就是一个由特定算法实现的垃圾收集器。

JavaScript注意事项及引起的内存泄漏原因

JavaScript注意事项及引起的内存泄漏原因

JavaScript注意事项及引起的内存泄漏原因JavaScript注意事项及引起的内存泄漏原因一、JavaScript中编码时要注意的几点1、尽量不要使用WITH尽管很方便,with需要附加的查找引用时间,因为它在编译的时候并不知道作用域的上下没。

有坏味道的代码:代码如下:with (test.object) {foo = 'Value of foo property of object';bar = 'Value of bar property of object';}性能优化后:代码如下:var myObj = test.object;myObj.foo = 'Value of foo property of object';myObj.bar = 'Value of bar property of object';2、不要在性能要求关键的函数中使用try-catch-finallytry-catch-finally在运行时每次都会在当前作用域创建一个新的变量,用于分配语句执行的异常。

异常处理应该在脚本的高层完成,在异常不是很频繁发生的地方,比如一个循环体的外面。

如果可能,尽量完全避免使用try-catch-finally。

有坏味道的代码:代码如下:var object = ['foo', 'bar'], i;for (i = 0; i < object.length; i++) {try {// 做自己的事} catch (e) {// 异常处理}}性能优化后:代码如下:var object = ['foo', 'bar'], i;try {for (i = 0; i < object.length; i++) {// 做些事情}} catch (e) {// 异常处理}3、null和undefinednull属于对象(object)的一种,意思是该对象为空;undefined 则是一种数据类型,表示未定义。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Js内存泄漏及解决方案在IE下的JS编程中,以下的编程方式都会造成即使关闭IE也无法释放内存的问题,下面分类给出:1、给DOM对象添加的属性是一个对象的引用。

范例:var MyObject = {};document.getElementById('myDiv').myProp = MyObject;解决方法:在window.onunload事件中写上: document.getElementById('myDiv').myProp = null;2、DOM对象与JS对象相互引用。

范例:function Encapsulator(element) {this.elementReference = element;element.myProp = this;}new Encapsulator(document.getElementById('myDiv'));解决方法:在onunload事件中写上: document.getElementById('myDiv').myProp = null;3、给DOM对象用attachEvent绑定事件。

范例:function doClick() {}element.attachEvent("onclick", doClick);解决方法:在onunload事件中写上: element.detachEvent('onclick', doClick);4、从外到内执行appendChild。

这时即使调用removeChild也无法释放。

范例:var parentDiv = document.createElement("div");var childDiv = document.createElement("div");document.body.appendChild(parentDiv);parentDiv.appendChild(childDiv);解决方法:从内到外执行appendChild:var parentDiv = document.createElement("div");var childDiv = document.createElement("div");parentDiv.appendChild(childDiv);document.body.appendChild(parentDiv);5、反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)。

范例:for(i = 0; i < 5000; i++) {hostElement.text = "asdfasdfasdf";}这种方式相当于定义了5000个属性!解决方法:其实没什么解决方法~~~就是编程的时候尽量避免出现这种情况咯~~说明:1、以上资料均来源于微软官方的MSDN站点,链接地址:/librar ... e_leak_patterns.asp大家可以到上面这个地址中看到详细的说明,包括范例和图例都有。

只是我英文不太好,看不太懂,如果我上述有失误或有需要补充的地方请大家指出。

2、对于第一条,事实上包括 element.onclick = funcRef 这种写法也算在其中,因为这也是一个对对象的引用。

在页面onunload时应该释放掉。

3、对于第三条,在MSDN的英文说明中好像是说即使调用detachEvent也无法释放内存,因为在attachEvent的时候就已经造成内存“LEAK”了,不过detachEvent后情况还是会好一点。

不知道是不是这样,请英文好的亲能够指出。

4、在实际编程中,这些内存问题的实际影响并不大,尤其是给客户使用时,客户对此绝不会有察觉,然而这些问题对于程序员来说却始终是个心病 --- 有这样的BUG心里总会觉得不舒服吧?能解决则给与解决,这样是最好的。

事实上我在这样顶级的JS源码站点中,在它们的源码里都会看到采用上述解决方式进行内存的释放管理。

理解并解决IE的内存泄漏方式Web开发的发展在过去一些的时候,Web开发人员并没有太多的去关注内存泄露问题。

那时的页面间联系大都比较简单,并主要使用不同的连接地址在同一个站点中导航,这样的设计方式是非常有利于浏览器释放资源的。

即使Web页面运行中真的出现了资源泄漏,那它的影响也是非常有限而且常常是不会被人在意的。

今天人们对Web应用有了高更的要求。

一个页面很可能数小时不会发生URL跳转,并同时通过Web服务动态的更新页面内容。

复杂的事件关联设计、基于对象的JScript和DHTML技术的广泛采用,使得代码的能力达到了其承受的极限。

在这样的情况和改变下,弄清楚内存泄露方式变得非常的急迫,特别是过去这些问题都被传统的页面导航方法给屏蔽了。

还算好的事情是,当你明确了希望寻找什么时,内存泄露方式是比较容易被确定的。

大多数你能遇到的泄露问题我们都已经知道,你只需要少量额外的工作就会给你带来好处。

虽然在一些页面中少量的小泄漏问题仍会发生,但是主要的问题还是很容易解决的。

泄露方式在接下来的内容中,我们会讨论内存泄露方式,并为每种方式给出示例。

其中一个重要的示例是JScript中的Closure技术,另一个示例是在事件执行中使用Closures。

当你熟悉本示例后,你就能找出并修改你已有的大多数内存泄漏问题,但是其它Closure相关的问题可能又会被忽视。

现在让我们来看看这些个方式都有什么:1、循环引用(Circular References) — IE浏览器的COM组件产生的对象实例和网页脚本引擎产生的对象实例相互引用,就会造成内存泄漏。

这也是Web页面中我们遇到的最常见和主要的泄漏方式;2、内部函数引用(Closures) — Closures可以看成是目前引起大量问题的循环应用的一种特殊形式。

由于依赖指定的关键字和语法结构,Closures调用是比较容易被我们发现的;3、页面交叉泄漏(Cross-Page Leaks) —页面交叉泄漏其实是一种较小的泄漏,它通常在你浏览过程中,由于内部对象薄计引起。

下面我们会讨论DOM插入顺序的问题,在那个示例中你会发现只需要改动少量的代码,我们就可以避免对象薄计对对象构建带来的影响;4、貌似泄漏(Pseudo-Leaks) —这个不是真正的意义上的泄漏,不过如果你不了解它,你可能会在你的可用内存资源变得越来越少的时候极度郁闷。

为了演示这个问题,我们将通过重写Script元素中的内容来引发大量内存的"泄漏"。

循环引用循环引用基本上是所有泄漏的始作俑者。

通常情况下,脚本引擎通过垃圾收集器(GC)来处理循环引用,但是某些未知因数可能会妨碍从其环境中释放资源。

对于IE来说,某些DOM对象实例的状态是脚本无法得知的。

下面是它们的基本原则:Figure 1: 基本的循环引用模型本模型中引起的泄漏问题基于COM的引用计数。

脚本引擎对象会维持对DOM对象的引用,并在清理和释放DOM对象指针前等待所有引用的移除。

在我们的示例中,我们的脚本引擎对象上有两个引用:脚本引擎作用域和DOM对象的expando 属性。

当终止脚本引擎时第一个引用会释放,DOM对象引用由于在等待脚本擎的释放而并不会被释放。

你可能会认为检测并修复假设的这类问题会非常的容易,但事实上这样基本的的示例只是冰山一角。

你可能会在30个对象链的末尾发生循环引用,这样的问题排查起来将会是一场噩梦。

如果你仍不清楚这种泄漏方式在HTML代码里到底怎样,你可以通过一个全局脚本变量和一个DOM对象来引发并展现它。

--------------------------------------------------------------------------------<html><head><script language="JScript">var myGlobalObject;function SetupLeak(){// First set up the script scope to element referencemyGlobalObject = document.getElementById("LeakedDiv");// Next set up the element to script scope referencedocument.getElementById("LeakedDiv").expandoProperty = myGlobalObject;}function BreakLeak(){document.getElementById("LeakedDiv").expandoProperty = null;}</script></head><body><div id="LeakedDiv"></div></body></html>你可以使用直接赋null值得方式来破坏该泄漏情形。

在页面文档卸载前赋null值,将会让脚本引擎知道对象间的引用链没有了。

现在它将能正常的清理引用并释放DOM对象。

在这个示例中,作为Web开发员的你因该更多的了解了对象间的关系。

作为一个基本的情形,循环引用可能还有更多不同的复杂表现。

对基于对象的JScript,一个通常用法是通过封装JScript对象来扩充DOM对象。

在构建过程中,你常常会把DOM对象的引用放入JScript对象中,同时在DOM对象中也存放上对新近创建的JScript对象的引用。

你的这种应用模式将非常便于两个对象之间的相互访问。

这是一个非常直接的循环引用问题,但是由于使用不用的语法形式可能并不会让你在意。

要破环这种使用情景可能变得更加复杂,当然你同样可以使用简单的示例以便于清楚的讨论。

<html><head><script language="JScript">function Encapsulator(element){// Set up our elementthis.elementReference = element;// Make our circular referenceelement.expandoProperty = this;}function SetupLeak(){// The leak happens all at oncenew Encapsulator(document.getElementById("LeakedDiv"));}function BreakLeak(){document.getElementById("LeakedDiv").expandoProperty = null;}</script></head><body><div id="LeakedDiv"></div></body></html>更复杂的办法还有记录所有需要解除引用的对象和属性,然后在Web文档卸载的时候统一清理,但大多数时候你可能会再造成额外的泄漏情形,而并没有解决你的问题。

相关文档
最新文档