一.垃圾收集

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垃圾收集与性能问题的更多相关文章

  1. Javascript 相关文章 —— 性能

    在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 概览 无论当前 JavaScript 代码是内嵌还是在外链文件中,页面的下载和渲染都必须停下来等待脚本执行完成.JavaS ...

  2. 优化JavaScript脚本的性能

    循环 循环是很常用的一个控制结构,大部分东西要依靠它来完成,在JavaScript中,我们可以使用for(;;),while(),for(in)三种循环,事实上,这三种循环中for(in)的效率极差, ...

  3. JavaScript垃圾收集-标记清除和引用计数

    JavaScript具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存. 垃圾收集机制原理:垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间), 周期性地执行这一操作:找出那些 ...

  4. 让你的Javascript提升70%性能

    现在的JavaScript代码要进行性能优化,通常使用一些常规手段,如:延迟执行.预处理.setTimeout等异步方式避免处理主线程,高大上一点的会使用WebWorker.即使对于WebWorker ...

  5. 2019-01-23 JavaScript实现ZLOGO: 性能改进

    主攻前文吴烜:JavaScript实现ZLOGO: 界面改进与速度可调的几个性能问题 在线演示: 圈3 源码仍在: program-in-chinese/quan3 之前是在绘制过程中计算每帧需要绘制 ...

  6. JavaScript大杂烩17 - 性能优化

    在上一节推荐实践中其实很多方面是与效率有关的,但那些都是语言层次的优化,这一节偏重学习大的方面的优化,比如JavaScript脚本的组织,加载,压缩等等. 当然在此之前,分析一下浏览器的特征还是很有意 ...

  7. Javascript之DOM性能优化

    原文地址:http://ce.sysu.edu.cn/hope/Item/140355.aspx 作者:陈古松 来源:本站原创 发布时间:2015-03-14 更新时间:2015-03-14  点击数 ...

  8. javascript垃圾收集

    javascript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存.而在C和C++之类的语言中,开发人员的一项基本任务就是手工跟踪内存的使用情况 ,这是造成许多问题的一个根 ...

  9. 网站性能,javascript性能相关知识点

    一.高性能网站 <高性能网站建设指南>一书中提出用户只有10%-20%最终用户响应时间是花在从web服务器获取html文档并传送到浏览器中,80%的时间都花在了等待页面组件中,由此提出了构 ...

随机推荐

  1. php中curl模拟post提交多维数组(转载)

    原文地址:http://www.cnblogs.com/mingaixin/archive/2012/11/09/2763265.html 今天需要用curl模拟post提交参数,请求同事提供的一个接 ...

  2. HARBOR 仓库 API功能接口

    1       项目管理 1.1     查看仓库中项目详细信息 curl -u "admin:Harbor12345" -X GET -H "Content-Type: ...

  3. int main()还是void main()

    按照新的C99标准,即使函数本身没有定义返回值,编译器也会加上,以返回给激发程序,运行状态.很多人甚至市面上的一些书籍,都使用了void main( ) ,其实这是错误的.C/C++ 中从来没有定义过 ...

  4. 隐藏C语言黑窗口

    隐藏C语言程序运行的黑窗口,加入预编译命令: (预编译,Linker链接,windows模式,黑窗口是dos模式) #pragma comment(linker,"/subsystem:\& ...

  5. 包装类和基本类型区别?(integer和int取值范围一样大)

    1.声明方式不同,int不需要new .Integer需要new 2.性质上根本不同点:int是基本数据类型.Integer是引用数据类型,它有自己的属性,方法 3.存储位置和方式不同:int是存储在 ...

  6. ABP官方文档翻译 6.1.2 MVC视图

    ASP.NET MVC 视图 介绍 AbpWebViewPage基类 介绍 ABP通过Abp.Web.Mvc nuget包集成到MVC视图.你可以如往常一样创建正常的MVC视图. AbpWebView ...

  7. Hadoop学习笔记五

    一.uber(u:ber)模式 MapReduce以Uber模式运行时,所有的map,reduce任务都在一个jvm中运行,对于小的mapreduce任务,uber模式的运行将更为高效. uber模式 ...

  8. POJ 2826 An Easy Problem?![线段]

    An Easy Problem?! Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12970   Accepted: 199 ...

  9. 谨慎升级到HTTPS

    我们的业务主要为两块,首先是h5商城,在商城里面会有很多很多的运营活动,点击进去是在后台配置的各种H5活动链接.而H5商城和运营活动是两个业务,两者的联系就是要在后台系统将运营活动的链接配置到商城中. ...

  10. mac 上node.js环境的安装与测试

    如果大家之前做过web服务器的人都知道,nginx+lua与现在流行的Node.js都是可以做web服务器的,前者在程序的写法和配置上要比后者麻烦,但用起来都是差不多.在这里建议大家如果对lua脚本语 ...