另外一种意外创建全局变量的情况.
function foo() { this.var1 = "potential accidental global";}// Foo 被调用时, this 指向全局变量(window)foo();在这种情况下调用foo, this被指向了全局变量window, 意外的创建了全局变量.
我们谈到了一些意外情况下定义的全局变量, 代码中也有一些我们明确定义的全局变量. 如果使用这些全局变量用来暂存大量的数据, 记得在使用后, 对其重新赋值为 null.
2. 未销毁的定时器和回调函数
在很多库中, 如果使用了观察着模式, 都会提供回调方法, 来调用一些回调函数. 要记得回收这些回调函数. 举一个 setInterval的例子.
var serverData = https://www.isolves.com/it/cxkf/yy/js/2019-12-06/loadData();setInterval(function() { var renderer = document.getElementById('renderer'); if(renderer) { renderer.innerhtml = JSON.stringify(serverData); }}, 5000); // 每 5 秒调用一次如果后续 renderer 元素被移除, 整个定时器实际上没有任何作用. 但如果你没有回收定时器, 整个定时器依然有效, 不但定时器无法被内存回收, 定时器函数中的依赖也无法回收. 在这个案例中的 serverData 也无法被回收.
3. 闭包
在 JS 开发中, 我们会经常用到闭包, 一个内部函数, 有权访问包含其的外部函数中的变量. 下面这种情况下, 闭包也会造成内存泄露.
var theThing = null;var replaceThing = function () { var originalThing = theThing; var unused = function () { if (originalThing) // 对于 'originalThing'的引用 console.log("hi"); }; theThing = { longStr: new Array(1000000).join('*'), someMethod: function () { console.log("message"); } };};setInterval(replaceThing, 1000);这段代码, 每次调用replaceThing时, theThing 获得了包含一个巨大的数组和一个对于新闭包someMethod的对象. 同时 unused 是一个引用了originalThing的闭包.
这个范例的关键在于, 闭包之间是共享作用域的, 尽管unused可能一直没有被调用, 但是someMethod 可能会被调用, 就会导致内存无法对其进行回收. 当这段代码被反复执行时, 内存会持续增长.
该问题的更多描述可见Meteor团队的这篇文章.
4. DOM 引用
很多时候, 我们对 Dom 的操作, 会把 Dom 的引用保存在一个数组或者 Map 中.
var elements = { image: document.getElementById('image')};function doStuff() { elements.image.src = https://www.isolves.com/it/cxkf/yy/js/2019-12-06/'http://example.com/image_name.png';}function removeImage() { document.body.removeChild(document.getElementById('image')); // 这个时候我们对于 #image 仍然有一个引用, Image 元素, 仍然无法被内存回收.}上述案例中, 即使我们对 image 元素进行了移除, 但是仍然有对 image 元素的引用, 依然无法对其进行内存回收.
另外需要注意的一个点是, 对于一个 Dom 树的叶子节点的引用. 举个例子: 如果我们引用了一个表格中的td元素, 一旦在 Dom 中删除了整个表格, 我们直观的觉得内存回收应该回收除了被引用的 td外的其他元素. 但是事实上, 这个td 元素是整个表格的一个子元素, 并保留对于其父元素的引用. 这就会导致对于整个表格, 都无法进行内存回收. 所以我们要小心处理对于 Dom 元素的引用.
小结我们平时在写代码的时候 , 可能很少去操作内存管理方面的事情 , 但我们要有内存管理方面的意思 , 特别是上面我提出的几种可能导致内存泄漏的情况 , 写代码的时候要谨慎 。
推荐阅读
- 您的Ping命令真的用对了吗?
- 什么是三层交换机?
- 如何区分百兆网线和千兆网线?
- 帝国cms调用当前访问会员的ID并显示该id的会员信息
- 善用SQL排名函数,让您的查询飞的更精彩
- 大清王朝的十二个铁帽子王 大清铁帽子王
- 路由器避坑指南
- 解决并发问题,数据库常用的两把锁!
- 白茶饼发霉后撬掉发霉的部分 茶叶发霉还能喝吗
- 原来传统的母亲节是这天 母亲节是哪一天