引用
垃圾回收算法主要依赖引用的概念,例如一个对象如果有另外一个对象的访问权限,这里就叫做一个对象引用另外一个对象,不论这里是显式还是隐式
引用计数垃圾收集
这个算最简单的回收算法,大致是某地对象当没有引用指向它的时候,也就是零指向,这个对象就会被垃圾回收机制回收
let arr = [1,2,3]
arr = null // [1,2,3]没有被引用,会被自动回收
循环引用,低版本浏览器
下面的例子中,两个对象相互引用,即使函数被调用完成,这里也不会被回收
function f() {
var o1 = {};
var o2 = {};
o1.p = o2; // o1 引用 o2
o2.p = o1; // o2 引用 o1. 这里会形成一个循环引用
}
f();
标记-清除算法
这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”
这个算法假定一个全局对象,然后定期的垃圾回收机制从全局开始,找所有从全局开始引用的对象,然后找这些对象引用的对象。这样就能找到所有可以获得的对象和不能获得的对象。
现代浏览器都使用了这个回收机制
自动GC的问题
自动化的GC很方便,但我们不知道它会什么时候执行,并且如果在使用程序的过程中,我们使用的大量的内存,然后GC没有运行,这时,程序就会假死或者卡顿,然后我们就需要手动做一些操作来触发内存回收
内存泄漏
本质上来说,内存泄漏就是不被需要的内存,因为某种原因,没有被回收或者释放
常见的内存泄漏
1.全局变量
function foo(arg) {
bar = "some text"; // 挂在到window上
this.arr = [1,2,3]; // this指向window
}
js中的全局变量,只有当页面被关闭后才会销毁
2.未销毁的定时器或回调函数
var serverData = loadData();
setInterval(function() {
var renderer = document.getElementById('renderer');
if(renderer) {
renderer.innerHTML = JSON.stringify(serverData);
}
}, 5000);
上面的代码中,如果后续renderer元素被移除了,然后我们没有清除定时器,这时定时器里面的函数和定时器本身都不会被回收
3.闭包
function do(){
let thing = 'eat'
return function(){
console.log(thing)
}
}
4.DOM引用
有些时候,当我们要对DOM元素进行操作的时候,会把DOM的引用放在一个数组或对象中
var elements = {
image: document.getElementById('image')
};
function doStuff() {
elements.image.src = 'http://example.com/image_name.png';
}
function removeImage() {
document.body.removeChild(document.getElementById('image'));
// 这个时候我们对于 #image 仍然有一个引用, Image 元素, 仍然无法被内存回收.
}
建议
谨慎使用DOM操作,主动删除没有业务意义的变量,合理使用性能监控工具,分析内存的使用状况
网友评论