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 相关文章推荐
基于Jquery的将DropDownlist的选中值赋给label的实现代码
May 06 Javascript
利用js实现选项卡的特别效果的实例
Mar 03 Javascript
js实现在页面上弹出蒙板技巧简单实用
Apr 16 Javascript
根据身份证号自动输出相关信息(籍贯,出身日期,性别)
Nov 15 Javascript
JavaScript中的关联数组问题
Mar 04 Javascript
JSON字符串转JSON对象
Jul 31 Javascript
JavaScript 七大技巧(一)
Dec 13 Javascript
JavaScript兼容浏览器FF/IE技巧
Aug 14 Javascript
JavaScript中this的四个绑定规则总结
Sep 26 Javascript
vue项目中jsonp跨域获取qq音乐首页推荐问题
May 30 Javascript
javascript实现对话框功能警告(alert 消息对话框)确认(confirm 消息对话框)
May 07 Javascript
JavaScript 引用类型实例详解【数组、对象、严格模式等】
May 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
3个PHP多维数组转为一维数组的方法实例
2014/03/13 PHP
PHP传值到不同页面的三种常见方式及php和html之间传值问题
2015/11/19 PHP
Joomla使用Apache重写模式的方法
2016/05/04 PHP
PHP基于新浪IP库获取IP详细地址的方法
2017/05/04 PHP
PHP simplexml_load_file()函数讲解
2019/02/03 PHP
javascript框架设计之浏览器的嗅探和特征侦测
2015/06/23 Javascript
jQuery插件Easyui设置datagrid的pageNumber导致两次请求问题的解决方法
2016/08/06 Javascript
微信小程序中实现一对多发消息详解及实例代码
2017/02/14 Javascript
jquery单击文字或图片内容放大并居中显示
2017/06/23 jQuery
javascript cookie的基本操作(添加和删除)
2017/07/24 Javascript
vue 使用html2canvas将DOM转化为图片的方法
2018/09/11 Javascript
VUE+Element UI实现简单的表格行内编辑效果的示例的代码
2018/10/31 Javascript
微信小程序实现的点击按钮 弹出底部上拉菜单功能示例
2018/12/20 Javascript
js判断浏览器的环境(pc端,移动端,还是微信浏览器)
2020/12/24 Javascript
详解vue3.0 的 Composition API 的一种使用方法
2020/10/26 Javascript
python中使用urllib2获取http请求状态码的代码例子
2014/07/07 Python
Python实现二分查找算法实例
2015/05/26 Python
Python正则表达式使用经典实例
2016/06/21 Python
Python提取网页中超链接的方法
2016/09/18 Python
Python  unittest单元测试框架的使用
2018/09/08 Python
python高效过滤出文件夹下指定文件名结尾的文件实例
2018/10/21 Python
详解Python绘图Turtle库
2019/10/12 Python
解析python 中/ 和 % 和 //(地板除)
2020/06/28 Python
详解pyqt5的UI中嵌入matplotlib图形并实时刷新(挖坑和填坑)
2020/08/07 Python
python获得命令行输入的参数的两种方式
2020/11/02 Python
详解如何使用Pytest进行自动化测试
2021/01/14 Python
CSS3用@font-face实现自定义英文字体
2013/09/23 HTML / CSS
html5的websockets全双工通信详解学习示例
2014/02/26 HTML / CSS
好药师网上药店:安全合法的网上药品零售药房
2017/02/15 全球购物
英国花园药房: The Garden Pharmacy
2017/12/28 全球购物
库房主管岗位职责
2013/12/31 职场文书
乡村卫生服务一体化管理实施方案
2014/03/30 职场文书
2014年青年教师工作总结
2014/12/17 职场文书
撤诉申请书法院范本
2015/05/18 职场文书
同意报考证明
2015/06/17 职场文书
六年级作文之关于梦
2019/10/22 职场文书