魔鬼的梦魇—验证IE中的JS内存泄露(二)
魔鬼的梦魇—验证IE中的JS内存泄露(二)
闭包往往是需要为内存泄露负责的,因为使用它会很容易产生不为程序员所发现的循环引用。父函数的参数和局部变量将会一直被冻结、引用和持有,知道闭包本身被释放,这并不是显而易见的。事实上闭包已经变成如此普遍的变成策略,以至于开发人员经常的深陷问题之中,但是已存的我们可以依赖使用的资源却很少。我们来看看这个使用了闭包的循环引用图,它详细的描述了闭包及其造成的没存泄露的由来,并且指出了这些循环引用是如何形成的。
一般情况下的循环引用时由于两个特定的对象彼此持有对方的引用造成的,但是闭包却不一样。它不是直接引用,而是其通过引入父函数的作用域信息而产生的。正常情况下,一个函数的局部变量和参数仅仅在函数被调用的生命周期内才能被使用。但是只要闭包存在的话,这些变量和参数就一直被引用,并且由于闭包的生命周期可能会超过父函数,所以这些局部变量和参数同样也会。在这个原理图(图1)中,只要父函数一执行完,就会释放对参数parameter1的引用。但是由于我们添加了一个闭包,这个闭包又添加了自己对parameter1的引用,但是这个引用直到这个闭包被释放的时候才会被释放。如果以正好将这个闭包绑定到一个事件,那么最终你就需要解除对这个事件的绑定。如果你将这个闭包绑定到DOM的属性expando,那么你最终页需要将这个属性重置为null。
图 1. 闭包导致内存泄露原理图
每调用一次函数就会产生一个新的闭包对象,所以调用两次父函数那么就是产生两个相互独立的闭包对象,每一个闭包都会引用产生自己的时候传入的参数。这种显而易见的特性是很容易导致内存泄露的。原理图对应的对象引用关系图如下(图2)
图 2. 闭包泄露原理图对象引用关系图
在这个模式中给出的例子也是使用的页面中的DOM元素,我们也是测试不到内存泄露的,因为本质上说这个也是由于循环引用导致。修改的可以导致泄露的代码如下,具体的验证图片就不贴出来了,有兴趣的话可以自己测试一下
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head>
<script language="JScript">
function AttachEvents(element) {
// This structure causes element to ref ClickEventHandler
element.attachEvent("onclick", ClickEventHandler);
function ClickEventHandler() {
// This closure refs element
}
}
function SetupLeak() {
// The leak happens all at once
AttachEvents(document.createElement("<div/>"));
}
function BreakLeak() {
}
</script>
</head\>
<body onload="SetupLeak()" onunload="BreakLeak()">
<div id="LeakedDiv"></div>
</body>
</html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现