javascript错误的认识不用关心内存管理


Posted in Javascript onDecember 15, 2012

介绍
低层次的语言,如C,具有低级别的内存管理命令,如:malloc()和free(),需要开发者手工释放内存。然而像javascript这样的高级语言情况则不同,对象(objects, strings 等)创建的时候分配内存,当他们不在使用的时候内存会被自动回收,这个自动回收的过程被称为垃圾回收。因为垃圾回收的存在,让javascript等高级语言开发者产生了一个错误的认识,以为可以不用关心内存管理。

内存生命周期
不管什么样的编程语言,内存的生命周期基本上是一致的。
分配你需要的内存
使用他进行读写操作
当内存不需要的时候,释放资源
步骤1和步骤2对于所有语言都一样,能明显觉察到。至于步骤3,低级别语言需要开发者显式执行。而对于像javascript这样的高级语言,这部分操作是交给解析器完成的,所以你不会觉察到。

javascript中的分配操作
值的初始化
在为变量赋值的时候,javascript会完成内存的分配工作。

var n = 123; // 为数字分配内存 
var s = "azerty"; // 为字符串分配内存 
var o = { 
a: 1, 
b: null 
}; // 为包含属性值的object对象分配内存 
var a = [1, null, "abra"]; // 为包含值的数组分配内存 
function f(a){ 
return a + 2; 
} // 为函数分配内存(函数是可调用的对象) 
// 函数表达式同样也是对象,存在分配内存的情况 
someElement.addEventListener('click', function(){ 
someElement.style.backgroundColor = 'blue'; 
}, false);

通过函数调用完成分配
一些函数当执行完毕之后,同样存在对象分配的情况发生。
var d = new Date(); 
var e = document.createElement('div'); // 分配一个 DOM 元素

一些方法会分配新值或者对象。
var s = "azerty"; 
var s2 = s.substr(0, 3); // s2 是一个新的字符串 
// 由于字符串是不变的,javascript会为[0, 3]范围的内容创建一个新的字符串 
var a = ["ouais ouais", "nan nan"]; 
var a2 = ["generation", "nan nan"]; 
var a3 = a.concat(a2); // 把 a 和 a2 结合在一起,产生一个新的数组

对值的使用
对值的使用,其实也就是对分配后的内存执行读写操作。这些操作包括:对变量或者对象的属性进行读写操作,或者向函数传递参数。

当不再需要的时候,释放内存
绝大多数内存管理的问题都发生在这个阶段。最难做的事情是,如何判定分配的内存不再需要。这往往需要开发者做出判定,程序在什么时候不再需要内存,并释放他所占资源。

高级语言的解析器中嵌入了一个叫做“垃圾收集器”的程序,他的工作是用来跟踪内存的分配和使用,判定内存是否被需要,在不再需要的时候执行资源释放操作。他只能获得一个近似值,因为判断一个内存是否被需要,这是个不确定的问题(不能通过一种算法解决)。

垃圾回收
正如上文所述,我们无法准确的做到自动判定“内存不再需要”。所以,垃圾回收对该问题的解决方案有局限性。本节将解释必要的概念,了解主要的垃圾收集算法和它们的局限性。

引用
垃圾回收中一个主要的概念是引用。在内存管理中,当一个对象无论是显式的还是隐式的使用了另外一个对象,我们就说他引用了另外一个对象。例如,javascript对象存在一个隐式的指向原型的引用,还有显式指向他的属性值的引用。

在这里,对象的概念超出了javascript传统意义上对象的概念,他还包括函数作用域和全局作用域。

使用引用计数算法的垃圾回收
下面要介绍的是一种最理想化的算法,引入了 “对象不再需要” 和 “没有其他对象引用该对象” 的概念。当该对象的引用指针变为0的时候,就认为他可以被回收。
例子:

var o = { 
a: { 
b:2 
} 
}; // 创建了两个对象. 一个对象(a)被另外一个对象(o引用的对象)引用,并把a作为他的属性 
// 该对象又被变量o引用 
// 很明显,这时没有对象能被回收 
var o2 = o; // 变量 o2 再次引用了该对象 
o = 1; // o 不再引用该对象,只有o2还在引用该对象 
var oa = o2.a; // oa引用 o2 的属性对象 a 
// 该对象被其他两个对象引用,分别是o2的属性a和oa变量 
o2 = "yo"; // 该对象已经不再被其他对象引用了,但是他的属性a任然被oa变量引用,所以他还不能被释放 
oa = null; // 现在属性a也不再被别的对象引用,该对象可以被回收了

限制:循环
该算法有其局限性,当一个对象引用另外一个对象,当形成循环引用时,即时他们不再被需要了,垃圾收集器也不会回收他们。
function f(){ 
var o = {}; 
var o2 = {}; 
o.a = o2; // o 引用 o2 
o2.a = o; // o2 引用 o 
return "azerty"; 
} 
f(); 
// 两个对象被创建,并形成相互引用 
// 函数调用结束之后,他们不会脱离函数作用域,虽然他们不会被使用,但不会被释放 
// 这是因为,引用计数的算法判定只要对象存在被引用的情况,那么就不能对其执行垃圾回收

现实中的例子
ie6、7中,在dom对象上使用引用计数的算法,这里会存在内存泄露的问题。
var div = document.createElement("div"); 
div.onclick = function(){ 
doSomething(); 
}; // div 通过 click 属性引用了事件处理程序 
// 当事件处理函数中访问了div变量的时候,会形成循环引用,将导致两个对象都不会被回收,造成内存泄露

标记 - 清除算法
他引入了“对象不再需要”和“对象不可访问(对象不可达)”的概念。该算法假设有一系列的根对象(javascript中的根对象就是全局对象),每隔一段时间,垃圾收集器就会从根对象开始,遍历所以他引用的对象,然后再遍历引用对象引用的对象,以此类推。使用这种方式,垃圾收集器可以获得所有可访问的对象,回收那些不可访问的对象。
这种算法比之前的算法好些,0引用的对象会被设置为不可访问对象,同时他也避免了循环引用造成的困恼。
截止2012年,大多数现代浏览器使用的是这种“标记-清除算法”的垃圾回收器。JavaScript垃圾收集领域(代/增量/并发/并行的垃圾收集),在过去的几年改善了与之相关的算法,但是垃圾收集算法本身(标记-清除算法)和“如何判定一个对象不再需要”并没有得以改善。

周期不再是一个问题
在第一个例子中,函数调用结束之后,这两个对象不会被全局对象引用,也不会被全局对象引用的对象引用。因此,他们会被javascript垃圾回收器标记为不可访问对象。这种事情同样也发生在第二个例子中,当div和事件处理函数被垃圾回收器标记为不可访问,他们就会被释放掉。

限制:对象需要明确的标记为不可访问
这种标记的方法存在局限,但是我们在编程中被没有接触到他,所以我们很少关心垃圾回收相关的内容。

Javascript 相关文章推荐
云网广告中的代码,提示出错,大家找找
Nov 21 Javascript
一个对于js this关键字的问题
Jan 09 Javascript
jquery+php随机生成红包金额数量代码分享
Aug 27 Javascript
JavaScript 实现的 zip 压缩和解压缩工具包Zip.js使用详解
Dec 14 Javascript
理解JS绑定事件
Jan 19 Javascript
javascript 广告移动特效的实现代码
Jun 25 Javascript
详解Vue-基本标签和自定义控件
Mar 24 Javascript
JS小球抛物线轨迹运动的两种实现方法详解
Dec 20 Javascript
Vue.js子组件向父组件通信的方法实例代码详解
Dec 10 Javascript
vue2.0自定义指令示例代码详解
Apr 25 Javascript
es6函数之rest参数用法实例分析
Apr 18 Javascript
vue 中使用print.js导出pdf操作
Nov 13 Javascript
jQuery 选择表格(table)里的行和列及改变简单样式
Dec 15 #Javascript
Jquery 选中表格一列并对表格排序实现原理
Dec 15 #Javascript
js 操作select和option常用代码整理
Dec 13 #Javascript
JavaScript 产生不重复的随机数三种实现思路
Dec 13 #Javascript
Javascript Boolean、Nnumber、String 强制类型转换的区别详细介绍
Dec 13 #Javascript
js onkeypress与onkeydown 事件区别详细说明
Dec 13 #Javascript
javascript 文件的同步加载与异步加载实现原理
Dec 13 #Javascript
You might like
PHP下几种删除目录的方法总结
2007/08/19 PHP
PHP中使用SimpleXML检查XML文件结构实例
2015/01/07 PHP
php ajax数据传输和响应方法
2018/08/21 PHP
PHP PDOStatement::getAttribute讲解
2019/02/01 PHP
Yii框架数据库查询、增加、删除操作示例
2019/10/14 PHP
详解将数据从Laravel传送到vue的四种方式
2019/10/16 PHP
jquery中dom操作和事件的实例学习 下拉框应用
2011/12/01 Javascript
JS小功能(列表页面隔行变色)简单实现
2013/11/28 Javascript
js实现获取鼠标当前的位置
2016/12/14 Javascript
原生js实现简单的Ripple按钮实例代码
2017/03/24 Javascript
vue 自定义组件 v-model双向绑定、 父子组件同步通信的多种写法
2017/11/27 Javascript
javascript Function函数理解与实战
2017/12/01 Javascript
微信小程序onLaunch异步,首页onLoad先执行?
2018/09/20 Javascript
vue-router 起步步骤详解
2019/03/26 Javascript
配置一个vue3.0项目的完整步骤
2019/04/26 Javascript
js图片无缝滚动插件使用详解
2020/05/26 Javascript
layer.msg()去掉默认时间,实现手动关闭的方法
2019/09/12 Javascript
[02:03]永远的信仰DOTA2 中国军团历届国际邀请赛回顾
2016/06/26 DOTA
Python内置函数reversed()用法分析
2018/03/20 Python
django输出html内容的实例
2018/05/27 Python
Python3实现对列表按元组指定列进行排序的方法分析
2018/12/22 Python
python GUI编程(Tkinter) 创建子窗口及在窗口上用图片绘图实例
2020/03/04 Python
python selenium操作cookie的实现
2020/03/18 Python
Python3.7下安装pyqt5的方法步骤(图文)
2020/05/12 Python
keras 简单 lstm实例(基于one-hot编码)
2020/07/02 Python
Python实现定时监测网站运行状态的示例代码
2020/09/30 Python
基于canvas使用贝塞尔曲线平滑拟合折线段的方法
2018/01/10 HTML / CSS
华为慧通面试题
2012/09/11 面试题
房地产销售经理岗位职责
2014/01/01 职场文书
二年级体育教学反思
2014/01/15 职场文书
《巨人的花园》教学反思
2014/02/12 职场文书
2014基建处领导班子“四风”对照检查材料思想汇报
2014/10/04 职场文书
幼儿园六一主持词
2015/06/30 职场文书
团结友爱主题班会
2015/08/13 职场文书
宣传部部长竞选稿
2015/11/21 职场文书
MySQL Router的安装部署
2021/04/24 MySQL