javascript垃圾收集与性能问题
一.垃圾收集
JavaScript具有自动垃圾收集功能,也就是说,执行环境会负责管理代码所占用的内存.
不同于C和类C语言,这些语言都需要手动监听内存的使用情况.JavaScript实现了自动管理内存,我们无需担心这个问题.
这种垃圾收集器的原理也很简单,就是找出不再继续使用的变量,然后释放其占用的内存.垃圾收集器会按照固定的时间间隔(或者代码的执行时间)来周期性的重复这个操作.
对于局部变量,我们都知道一旦在函数运行完成之后,函数和局部变量就立即被销毁,所以,此时局部变量也就没有存在的意义了.因此,我们可以释放局部变量的内存.垃圾收集器会自动为无用的变量做上标记,然后回收其占用的内存.具体所用到的策略会因浏览器而异.但总的来说,就只有二个策略.
1.标记清除
标记清除是JavaScript中最常见的垃圾收集方式了.当变量进入一个执行环境,这个变量就会被标记为进入环境,因此,永远都不能释放进入环境的变量,因为只要执行流进入相应的环境,还有可能会运用到它们,当变量离开环境之后,就会将其标记为离开环境..
可以使用任意方式标记一个变量,因此,如何标记变量并不重要,重要的是采用什么策略.
垃圾收集器在运行的时候会给存储在内存中的所有变量加上标记.然后,它会去掉环境中的变量以及被环境中变量引用的变量的标记.在此之后,加上标记的变量就是被视为准备删除的变量,因为环境中的变量已经无法访问到这些变量了,最后垃圾收集器完成清除内存的工作,销毁哪些带标记的值并回收它们所占用的内存空间.
2.引用计数
另一种不太常见的垃圾收集策略叫做引用计数.引用计数的含义就是跟踪每个值被引用的次数.当声明一个变量并将这个变量赋一个引用类型的值时,引用次数就为1,如果将相同的值又被赋予另一个变量,则引用次数记为2,如果包含这个值引用的变量又引用其它值,则减1.当这个值的引用次数变成0时,则说明无法访问这个值了,就会回收这个值所占用的内存.这样,当垃圾收集器下次运行时,就会自动释放那些引用次数为0的值所占用的内存.
Netscape Navigator3.0是最早使用引用计数策略的浏览器,然而很快这个策略就暴露了一个严重的问题——循环引用.所谓循环引用,指的就是一个对象A包含指向一个对象B的指针时,对象B也有包含指向对象A的指针引用.如下图一个示例:

如上图所示,person对象和people对象都通过各自的属性相互引用,也就是说这两个对象的引用次数始终都是2.如果是采用标记清除的策略,因为函数执行完成之后,这两个对象都离开了作用域,因此这种相互引用还并不是问题.但在采用引用次数策略的时候,由于引用次数始终都是2,始终都不为0,假如这个函数被多次调用的话,就会占用大量内存得不到回收.
所以,Netscap4.0就放弃了引用计数的策略,而采用标记策略,但这个问题并没有终结.
因为IE中有一部分对象并不是原生JavaScript对象,比如BOM和DOM的对象都是使用C++以COM(Component Object Model,组件对象模型)对象的形式实现的,COM对象的垃圾收集策略就是采用引用计数实现的.也就是说,只要在IE中涉及到COM对象,就会存在循环引用的问题.
请看如下一个示例:

这个示例就是在DOM对象与原生JavaScript对象中间创建了一个循环引用.变量obj有一个属性指向变量div的DOM对象,而变量div也有一个属性回指obj.由于存在循环引用,因此即使将DOM移除,也不会被回收掉.
为了避免这种问题,最好是在不使用它们的时候手工断开它们之间的链接,即将它们的值各自设置为null即可.如下图所示:
IE9将BOM和DOM都转换成了真正的JavaScript对象.这样也就解决了两种垃圾算法并存导致的问题,还解决了内存泄漏现象.
二.性能问题
JavaScript垃圾收集器是周期性的运行,,如果为变量分配的内存数量很可观,回收工作量也是相当大的.因此,在这种情况下,确定垃圾收集器的时间间隔也成为了一个重要的问题.
IE的垃圾收集器是根据内存分配量运行的,具体点说,就是达到256个变量,4096个对象(或数组)字面量和数组元素(slot)或者64kb的字符串,这样的临界值,垃圾收集器就会运行.这样造成的一个问题就是垃圾收集器不得不频繁的运行,因为一旦一个脚本包含许多变量,该脚本就会在其生命周期内保存许多变量,由此便引发了严重的性能问题.
IE7的发布改进了这个问题,它改变了垃圾收集的工作方式.达到临界值被调整为动态修正,初始值与IE6是一样的,如果内存分配量低于15%,则临界值就会加倍.如果回收了85%的内存分配量,则重置临界值为默认值.这样调整大大提升了性能.
其实,在有的浏览器中可以触发垃圾收集过程,在IE中,调用window.CollectGarbage()方法可立即执行.在Opera7及更高版本中,调用window.opera.collect()也会启动垃圾收集例程.
三.管理内存
尽管开发人员可以不用担心内存管理的问题,在使用具备垃圾收集机制的语言编写程序.但是JavaScript在进行内存管理及垃圾收集时面临的问题还是有点不同的.其中最主要的一个问题就是分配给web浏览器的可用内存数量通常要比分配给桌面应用程序的少.
这样的意义在于对安全方面考虑,目的是防止JavaScript的网页耗尽全部系统内存而导致系统崩溃.内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量.
所以,确保最少的内存可以给页面带来更好的性能,优化内存最好的方式,就是可以为执行中的代码保存必要的数据.一旦数据不再有用,那么最好将其值设置为null来释放其引用,这个做法也被叫做解除引用.这个做法适合大多数全局变量和全局对象的属性,当然局部环境的变量会自动解除其引用,所以不必如此做.
来看下图一个示例:
上图示例,变量o获取到了函数返回的值,而在createName()函数内部,通过传入一个参数name,可以赋给局部变量obj的firstname属性,当函数执行完毕,变量obj就会立即被销毁,也就是自动解除了引用,但对于变量o而言,因为是全局变量,所以需要我们手动去解除引用,将值设置为null就行了.当然解除一个引用并不是自动回收它占用的内存.解除引用的真正作用是让值脱离执行环境,从而方便垃圾收集器下次运行时回收.
javascript垃圾收集与性能问题的更多相关文章
- Javascript 相关文章 —— 性能
在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 概览 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaS ...
- 优化JavaScript脚本的性能
循环 循环是很常用的一个控制结构,大部分东西要依靠它来完成,在JavaScript中,我们可以使用for(;;),while(),for(in)三种循环,事实上,这三种循环中for(in)的效率极差, ...
- JavaScript垃圾收集-标记清除和引用计数
JavaScript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存. 垃圾收集机制原理:垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间), 周期性地执行这一操作:找出那些 ...
- 让你的Javascript提升70%性能
现在的JavaScript代码要进行性能优化,通常使用一些常规手段,如:延迟执行.预处理.setTimeout等异步方式避免处理主线程,高大上一点的会使用WebWorker.即使对于WebWorker ...
- 2019-01-23 JavaScript实现ZLOGO: 性能改进
主攻前文吴烜:JavaScript实现ZLOGO: 界面改进与速度可调的几个性能问题 在线演示: 圈3 源码仍在: program-in-chinese/quan3 之前是在绘制过程中计算每帧需要绘制 ...
- JavaScript大杂烩17 - 性能优化
在上一节推荐实践中其实很多方面是与效率有关的,但那些都是语言层次的优化,这一节偏重学习大的方面的优化,比如JavaScript脚本的组织,加载,压缩等等. 当然在此之前,分析一下浏览器的特征还是很有意 ...
- Javascript之DOM性能优化
原文地址:http://ce.sysu.edu.cn/hope/Item/140355.aspx 作者:陈古松 来源:本站原创 发布时间:2015-03-14 更新时间:2015-03-14 点击数 ...
- javascript垃圾收集
javascript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存.而在C和C++之类的语言中,开发人员的一项基本任务就是手工跟踪内存的使用情况 ,这是造成许多问题的一个根 ...
- 网站性能,javascript性能相关知识点
一.高性能网站 <高性能网站建设指南>一书中提出用户只有10%-20%最终用户响应时间是花在从web服务器获取html文档并传送到浏览器中,80%的时间都花在了等待页面组件中,由此提出了构 ...
随机推荐
- VisionPro笔记:色彩区分
VisionPro:色彩区分 来自:blog.sina.com.cn/yangchao168 利用色彩来区分物体这类的项目没做过,总觉得很难,尤其是涉及到RGB和HSI等.看到VisionPro中有这 ...
- PDO错误调试
在服务器上用PDO操作数据库,怎么都获取不到数据,query语句返回null,但是同样的代码在本地运行无误.SO,开始找bug. <?php $host='localhost'; $dbname ...
- AutoCAD开发选择----ObjectARX还是.net API(转载)
本文基于AutoCAD 2006新推出的.NET API为工具,介绍了在.NET平台下对AutoCAD进行二次开发的技术,并与目前常用的VBA.ObjectARX作了对比.同时讨论了如何弥补.NET ...
- Linq to SQL 中实现模糊查询
list = list.Where(i => i.Name.Contains(empName)).ToList();
- 在IAR下移植CC2650 contiki工程
与Instant Contiki相比,在Windows的IAR下开发可以在线仿真,下载也更方便,因此我想把BLEach的工程移植到IAR下.弄了好几天总算编译并且下载成功了,参考了[这篇TI的wiki ...
- BZOJ 3544: [ONTAK2010]Creative Accounting [set]
给定一个长度为N的数组a和M,求一个区间[l,r],使得$(\sum_{i=l}^{r}{a_i}) mod M$的值最大,求出这个值,注意这里的mod是数学上的mod 这道题真好,题面连LaTeX都 ...
- SDN第四次作业
作业链接 1.阅读 了解SDN控制器的发展 http://www.sdnlab.com/13306.html http://www.docin.com/p-1536626509.html 了解ryu控 ...
- python爬虫(1)——urllib包
人生苦短,我用python! 一.关于爬虫 鉴于我的windos环境使用命令行感觉非常不便,也懒得折腾虚拟机,于是我选择了一个折中的办法--Cmder.它的下载地址是:cmder.net Cmder是 ...
- php读取文件内容的三种方法
<?php //**************第一种读取方式***************************** 代码如下: header("content-type:text/h ...
- SQL Server 页面查询超时(SOS_SCHEDULER_YIELD等待)
一.问题概述 问题大概是这样的,有一个功能页面经常查询超时,有时候就算能查询出来也要很长的时间,但是有时又会很快.遇到的这种问题在排除掉网络原因之后基本上可以从查询语句上去找原因. 编译查询SQL语句 ...