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%的时间都花在了等待页面组件中,由此提出了构 ...
随机推荐
- 网站静态化处理—web前端优化—上(11)
网站静态化处理这个系列马上就要结束了,今天我要讲讲本系列最后一个重要的主题web前端优化.在开始谈论本主题之前,我想问大家一个问题,网站静态化处理技术到底是应该归属于web服务端的技术范畴还是应该归属 ...
- 关键字voltale
***volatile在多线程用的最多.*** #include<stdio.h> #include<stdlib.h> int main() { ; i < ; i++ ...
- Electron应用使用electron-builder配合electron-updater实现自动更新(windows + mac)
发客户端一定要做的就是自动更新模块,否则每次版本升级都是一个头疼的事.下面是Electron应用使用electron-builder配合electron-updater实现自动更新的解决方案. 1.安 ...
- Spring MVC执行的流程
1.Spring MVC应用的开发步骤 a.在web.xml文件中定义前端控制器DispatcherServlet来拦截用户请求.由于Web应用是基于请求/响应架构的应用,所以 不管哪个MVC Web ...
- PyCharm运行Nosetests并导出测试报告
1. Pycharm运行Nosetests PyCharm可以使用两种方法,运行Nosetests测试文件: 1) 图形用户界面GUI a) 在PyCharm中,选中测试文件,如Tests/test_ ...
- 窗口缩小div内容隐藏看不到怎么解决?
div的宽度设置为100%,并设置其背景颜色,但当窗口发生变化出现横向滚动条,拉滚动条的时候发现右面是空白的. 解决方法:body{min-width:1024px},给body加上一个最小宽度.ie ...
- linux下安装phpunit简单方法
现在安装phpunit相当简单,只需要下载phar压缩格式的phpunit文件,给个执行权限,就可以执行了 以下是一段官方安装文档 wget https://phar.phpunit.de/phpun ...
- ABP官方文档翻译 3.7 领域事件(事件总线)
领域事件(事件总线) 事件总线 注入IEventBus 获取默认实例 定义事件 预定义事件 处理异常 实体更改 触发事件 处理事件 处理基础事件 处理者异常 处理多个事件 注册处理者 自动 手动 取消 ...
- mybatis-generator 根据表生成对应文件
1 创建maven工程 2.编辑.pom文件 <?xml version="1.0" encoding="UTF-8"?> <project ...
- 2017年总结的前端文章——border属性的多方位应用和实现自适应三角形
border属性是在实际的应用中使用频率比较高的一个属性,除了作为边框使用,利用border属性的一些特征以及表现方式,可以在实现一些比较常见的效果(如等高布局,上下固定内容滚动布局和绘制CSS图标等 ...