JavaScript 闭包都会闭包导致内存泄露露吗

function fors(){
obj_a = obj_b;
obj_b.attr = obj_a;
function fors(){
obj_b = {};
obj_b.attr = obj_b;
上面是两个个很显示的循环引用,IE中产生了内存泄露,由于IE的内存回收机制,导至会长期占用内存而不能释放。
但闭包的内存泄露,有些隐蔽。因为闭包的循环引用,是间接的。
function iememery(){
var js_obj = document.createElement("div");
js_obj.oncontextmenu = function(){ return false;}
}&body onload="iememery()"&
从表面上看,没有任何循环引用。但上面是一个闭包,根据闭包的特性,内部函数有权访问外部函数的变量对象。所以当iememery()执行之后:
js_obj是一个DOM元素的引用,DOM元素它长期在网页当中,不会消失,而这个DOM元素的一属性oncontextmenu,又是内部的函数引用(闭包),而这个匿名函数又和js_obj之间有隐藏的关联(作用域链)
所以形成了一个,循环引用.即:
js_obj.oncontextmenu 间接引用到 js_obj 也就是说,这个对象的一个属性,又间接的引用了自己。
只要有循环引用,就会在IE下产生内存泄露。打开你的windows任务管理器,在IE中不停刷新含有这个代码的html页面,看看Iexploer进程的内存占用情况,一直上升,且不会自动回收(降低);
解决办法:
function iememery(){
var js_obj = document.createElement("div");
js_obj.oncontextmenu = function(){ return false;};
      js_obj.oncontextmenu = null;//加上这句,断开引用 }
当IE中发生js对象与dom对象直接的循环引用,并且之后没有引用指向他们,如果是IE 6, 内存泄漏,直到关闭IE进程为止如果是IE 7,内存泄漏, 直到离开当前页面为止如果是IE 8, GC回收器回收他们的内存,无论当前是不是compatibility模式。之前的IE js引擎里的GC回收器只能处理js对象,不能处理DOM对象。由于IE9之前的版本对JScript对象和COM对象使用不同的垃圾收集例程,因此闭包在IE的这些版本中会导致如上问题。这个匿名函数作为element元素事件处理程序,形成闭包的状态就会保存对父层函数内活动对象的引用,只要匿名函数存在,element的引用数至少也是1,因此它所占用的内存就永远不会被回收。注意,闭包会引用包含函数的整个活动对象,即使闭包不直接引用element,包含函数的活动对象中也仍然会保存一个引用。因此,有必要把使用完的element变量设置为null,解除对DOM对象的引用,确保正常回收其占用的内存。
阅读(...) 评论()JavaScript&js闭包所用的场合以及优缺点
先上段代码:
function a()
&&& //函数b
&&& function
alert(++i);
&&& return
&&& //函数c
&&& var c =
代码特点:
1、函数b嵌套在函数a内部;
2、函数a返回函数b。
代码中函数a的内部函数b,被函数a外面的一个变量c引用的时候,这就叫创建了一个闭包。有时候函数b也可以用一个匿名函数代替来返回,即return
function(){};
优点:1.保护函数内的变量安全,加强了封装性 2.在内存中维持一个变量(用的太多就变成了缺点,占内存)
闭包之所以会占用资源是当函数a执行结束后, 变量i不会因为函数a的结束而销毁, 因为b的执行需要依赖a中的变量。
不适合场景:返回闭包的函数是个非常大的函数
闭包的典型框架应该就是jquery了。
闭包是javascript语言的一大特点,主要应用闭包场合主要是为了:设计私有的方法和变量。
这在做框架的时候体现更明显,有些方法和属性只是运算逻辑过程中的使用的,不想让外部修改这些属性,因此就可以设计一个闭包来只提供方法获取。
闭包的缺点就是常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
1. 逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑。
2. 方便调用上下文的局部变量。
3. 加强封装性,第2点的延伸,可以达到对变量的保护作用。
闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。javascript关于内存泄露的一个实例问题求解?_百度知道
javascript关于内存泄露的一个实例问题求解?
function assignHandler() {
var element = document.getElementById(&someElement&);
element.onclick = function() {
alert(element.id);
}}以上代码创建了一个作为element元素事件处理程序的闭包,而这个闭包则又创建了一个循环引用。由于匿名函数保存了一个对assignHandler()的活动对象的应用,因此就无法减少element的引用数。-----这句话要怎样理解,在下不懂此处的“循环引用”?
提问者采纳
首先,你需要先更正/准确化对所谓闭包的理解,参见我在这里的回答:当你明确的理解了闭包之后,再来看你上面这段代码,就会发现问题了。&&&&element.onclick&=&function()&{&&&&&&&&alert(element.id);&&&&}这里,element 对象的 onclick 指向了你的匿名函数,所以我们首先可以明确,在 element 对象释放之前,你这个匿名函数是肯定释放不了的了。问题是 element 对象能在将来某个时刻被释放吗?不能!因为你的匿名函数里又引用了 element 对象!也就是说,element 对象引用了你的匿名函数,你的匿名函数又引用了 element。结果就形成了环形引用。这就是问题所在。这么来看,这里就形成了内存泄漏。但是再仔细深究,其实也不尽然。因为虽然这里形成了环形引用,但是现代垃圾回收器其实并不是简单的只看一个对象的引用计数是否为0来判断能不能回收的。而是要看是否存在一条从根对象指向该对象的路径来判断的。简单的来说就是,对于现代垃圾回收器,这种简单的环状引用不会造成内存泄漏。
提问者评价
真的非常感谢!!
其他类似问题
为您推荐:
内存泄露的相关知识
其他1条回答
给你找的图撒,和你这个其实一样因为你函数内层是个事件,也就不需要return出来由于事件内层调用了外层的element,且因为事件对象一直存在导致外层的element引用数至少为1,无法被释放
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁查看 Node.js 中的内存泄露 - 博客 - 伯乐在线
& 查看 Node.js 中的内存泄露
英文原文:,翻译:
这篇文章是由Mozilla的Identity团队带来的 系列文章的首篇,该团队上个月发布了的第一个测试版本。在开发Persona时我们构建了一系列的工具,包括了从调试,到本地化,到依赖管理以及更多的方面。在这一系列的文章中我们将与社区分享我们的经验和这些工具,这对任何想用node.js建立一个高可用性服务的人都很有用。我们希望您能喜欢这些文章,并期待看到您的想法和贡献。
我们将从一篇关于Node.js的实质性问题:内存泄漏的主题文章开始。我们会介绍
— 一个帮助发现并隔离Node中的内存泄漏问题的函数库。
为什么自寻烦恼?
关于追踪内存泄漏问得最多的问题就是,“为什么要自寻烦恼?”。难道没有更紧迫的问题需要先解决吗?为什么不选择不时地重启服务,或为之分配更多的RAM?为了回答这些问题,我们提出了以下三点建议:
1.也许你不在乎不断增长的内存占用,但V8在乎(V8是Node运行时的引擎)。随着内存泄漏的增长,V8对垃圾收集器越来越具有攻击性,这会使你的应用运行速度变慢。所以,在Node上,内存泄漏会损害程序性能。
2.内存泄漏可能触发其他类型的失败。内存泄漏的代码可能会持续的引用有限的资源。你可能会耗尽文件描述符;你还可能会突然不能建立新的数据库连接。这类问题可能在你的应用耗尽内存前很早就会暴露出来,但它仍然会是你陷入困境。
3.最后,你的应用迟早会崩溃,并且在你的应用受到欢迎时肯定会发生。所有人都会在Hacker News上嘲笑你,讽刺你,这样你就悲剧了。
溃千里之堤的蚁穴在哪里?
在构建复杂应用的时候,很多地方都可能发生内存泄露。 可能是最广为人知也是最声名狼藉的。因为闭包保留了对其作用域内的东西的引用,而这正是通常的内存泄露之源。
闭包泄露往往只有在有人去寻找它们的时候才能发现。但是在Node的异步世界里,我们随时随地的通过回调函数不停的生成闭包。如果这些回调函数没有在创建后立刻使用,分配的内存就会持续增长,那些看起来没有内存泄露问题的代码也会产生泄露。而这种问题更难发现。
你的应用也可能由于上游代码的问题导致内存泄露。也许你能定位到出现内存泄露的代码,但是你可能只能眼巴巴地盯着你那完美无缺的代码然后困惑于这到底是怎么泄露的!
正是这些难以定位的内存泄露促使我们想要一个node-memwatch这样的工具。传说几个月以前,我们的把他自己锁在一个小房间里两天,试着追踪一个在压力测试下变得非常明显的内存泄露问题。(顺便说下,尽请期待Lloyd即将到来的关于负荷测试的文章)
经过两天的努力,他终于发现了Node内核中的元凶:http.ClientRequest中的事件监听器没有被释放。(最终只有两个但却至关重要的字母)。正是这次痛苦的经历促使Lloyd想要写一个能够帮助查找内存泄露的工具。
内存泄露定位工具
现在已经有许多好用且不断增强的工具用于定位Node.js应用的内存泄露。下面是其中的一些:
Jimb Esser的,它使用了GCC的mtrace工具来分析堆的使用。
Dave Pacheco的对V8的堆抓取了一张快照并把所有的东西序列化进一个巨大的JSON文件。它还包含了一些分析研究快照结果的JavaScript工具。
Danny Coates的和提供了绑定在Node中的V8分析器和一个基于WebKit Web Inspector的debug界面。
Felix Gnass的分支。
Felix Geisend?rfer的是一个又短又酷的v8-profiler和node-debugger使用教程。同时也是目前最先进的Node.js内存泄露调试技术指南。
Joyent的SmartOS平台,它提供了大量用于的工具。
上面的这些工具我们都很喜欢,但是没有一个适用于我们的场景。Web Inspector对于开发中的应用非常棒,但是很难用于热部署的场景,尤其是在多服务器和涉及子进程的时候。同样的,在长时间高负载运行中出现的内存泄露也很难复现。像dtrace和libumem这样的工具虽然让人印象深刻,但是不是所有的操作系统都能用。
Enternode-memwatch
我们需要一个跨平台的调试库,当我们的程序可能存在内存泄漏时,它不需要设备告诉我们,并且会帮我们找到哪里存在泄漏。所以我们实现了node-memwatch。
它给我们提供三件东西:
一个‘泄漏’事件发射器
memwatch.on('leak', function(info) {
// look at info to find out about what might be leaking
一个‘状态’事件发射器
var memwatch = require('memwatch');
memwatch.on('stats', function(stats) {
// do something with post-gc memory usage stats
一个堆内存区分类
var hd = new memwatch.HeapDiff();
// your code here ...
var diff = hd.end();
并且还有一个在测试时很有用处的,可以触发垃圾收集器的功能。好吧,一共四点。
var stats = memwatch.gc();
memwatch.on(‘stats’, …): Post-GC堆统计
node-memwatch能够在任何一个JS对象分配之前,紧随着一次完整的垃圾回收和内存压缩发出一个内存使用样本。(它使用了V8的post-gc钩子,V8::AddGCEpilogueCallback,来在每次垃圾回收触发时收集堆使用信息)
统计数据包括:
usage_trend(使用趋势)
current_base(当前基数)
estimated_base(预期基数)
num_full_gc (完整的垃圾回收次数)
num_inc_gc (增长的垃圾回收次数)
heap_compactions (内存压缩次数)
min (最小)
max (最大)
这里有一个展示存在内存泄露的应用的数据看起来是什么样的例子。下面的图表随着时间追踪内存的使用。疯狂的绿线展示了process.memoryUsage()报告的内容。红线展示了node_memwatch报告的current_base。左下侧的盒子展示了附加信息。
注意Incr GCs非常高。那说明V8在拼命的尝试清理内存。
memwatch.on(‘leak’, …): 堆分配趋势
我们定义了一个简单的侦测算法来提醒你应用程序可能存在内存泄漏。即如果经过连续五次GC,内存仍被持续分配而没有得到释放,node-memwatch就会发出一个leak事件。事件的具体信息格式是明了易读的,就像这样:
{ start: Fri, 29 Jun :13 GMT,
end: Fri, 29 Jun :33 GMT,
growth: 67984,
reason: 'heap growth over 5 consecutive GCs (20s) - 11.67 mb/hr' }
memwatch.HeapDiff(): 查找泄漏元凶
最后,node-memwatch能比较堆上对象的名称和分配数量的快照,其对比前后的差异可以帮助找出导致内存泄漏的元凶。
var hd = new memwatch.HeapDiff();
// Your code here ...
var diff = hd.end();
对比产生的内容就像这样:
&before&: {
&nodes&: 11625,
&size_bytes&: 1869904,
&size&: &1.78 mb&
&after&: {
&nodes&: 21435,
&size_bytes&: 2119136,
&size&: &2.02 mb&
&change&: {
&size_bytes&: 249232,
&size&: &243.39 kb&,
&freed_nodes&: 197,
&allocated_nodes&: 10007,
&details&: [
&what&: &Array&,
&size_bytes&: 66688,
&size&: &65.13 kb&,
&what&: &Code&,
&size_bytes&: -55296,
&size&: &-54 kb&,
&what&: &LeakingClass&,
&size_bytes&: 239952,
&size&: &234.33 kb&,
&+&: 9998,
&what&: &String&,
&size_bytes&: -2120,
&size&: &-2.07 kb&,
HeapDiff方法在进行数据采样前会先进行一次完整的垃圾回收,以使得到的数据不会充满太多无用的信息。memwatch的事件处理会忽略掉由HeapDiff触发的垃圾回收事件,所以在stats事件的监听回调函数中你可以安全地调用HeapDiff方法。
在下图中,我们加上了堆内存对象分配数量排行:
下一步怎么做
node-memwatch提供了:
准确的内存使用情况跟踪
疑似内存泄漏通知
堆差异比较
这是跨平台的
并且不要求任何额外的设备
我们想要它的功能更多。特别是,我们希望node-memwatch能够提供一些导致内存泄漏的对象的使用案例(例如,变量名称,数组下标或闭包代码)。
我们希望您能在调试Node应用程序泄漏问题时发现memwatch很好用,也希望您能复制一份代码并帮助我们做得更好。
可能感兴趣的话题
为作者带来更多读者;为读者筛选优质内容;专注IT互联网。
最新评论(期待您也参与评论)
汇集优质的Python技术文章和资源。人生苦短,我用Python!
JavaScript, CSS, HTML5 这里有前端的技术干货!
关注安卓移动开发业界动态,分享技术文章和优秀工具资源。
关注iOS移动开发业界动态,分享技术文章和优秀工具资源。
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线博客团队正试图以我们微薄的力量,把优秀的原创/译文分享给读者,做一个小而精的精选博客,为“快餐”添加一些“营养”元素。
欢迎关注更多频道
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选博客文章
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
(加好友请注明来意)
网站使用问题
请在询问或者反馈
& 2015 伯乐在线
赞助云主机页面导航:
→ 正文内容 IE内存泄露
Javascript 闭包引起的IE内存泄露分析
Javascript 闭包引起的IE内存泄露分析,js_obj是一个DOM元素的引用,DOM元素它长期在网页当中,不会消失,而这个DOM元素的一属性
代码如下: function fors(){ obj_a = obj_b; obj_b.attr = obj_a; }
代码如下: function fors(){ obj_b = {}; obj_b.attr = obj_b; }
上面是两个个很显示的循环引用,IE中产生了内存泄露,由于IE的内存回收机制,导至会长期占用内存而不能释放。 但闭包的内存泄露,有些隐蔽。因为闭包的循环引用,是间接的。
代码如下: function iememery(){ var js_obj = document.createElement("div"); js_obj.oncontextmenu = function(){} } &body onload="iememery()"&
从表面上看,没有任何循环引用。但上面是一个闭包,根据闭包的特性,内部函数有权访问外部函数的变量对象。所以当iememery()执行之后: js_obj是一个DOM元素的引用,DOM元素它长期在网页当中,不会消失,而这个DOM元素的一属性oncontextmenu,又是内部的函数引用(闭包),而这个匿名函数又和js_obj之间有隐藏的关联(作用域链) 所以形成了一个,循环引用.即: js_obj.oncontextmenu 间接引用到 js_obj 也就是说,这个对象的一个属性,又间接的引用了自己。 只要有循环引用,就会在IE下产生内存泄露。打开你的windows任务管理器,在IE中不停刷新含有这个代码的html页面,看看Iexploer进程的内存占用情况,一直上升,且不会自动回收(降低); 解决办法:
代码如下: function iememery(){ var js_obj = document.createElement("div"); js_obj.oncontextmenu = function(){};      js_obj.oncontextmenu =//加上这句,断开引用 }
当IE中发生js对象与dom对象直接的循环引用,并且之后没有引用指向他们, 如果是IE 6, 内存泄漏,直到关闭IE进程为止 如果是IE 7,内存泄漏, 直到离开当前页面为止 如果是IE 8, GC回收器回收他们的内存,无论当前是不是compatibility模式。 之前的IE js引擎里的GC回收器只能处理js对象,不能处理DOM对象。
您可能感兴趣的文章:
上一篇:下一篇:
最 近 更 新
热 点 排 行
12345678910

我要回帖

更多关于 javascript 闭包写法 的文章

 

随机推荐