一.垃圾收集

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. java 如何将 word,excel,ppt如何转pdf --openoffice (1)

    承上启下,可折叠 上一篇说的是:服务器是windows server时,用jacob将msoffice(指的是word,excel,ppt)转换成pdf. 若被部署项目的服务器是centOS等linu ...

  2. springboot(十九):使用Spring Boot Actuator监控应用

    微服务的特点决定了功能模块的部署是分布式的,大部分功能模块都是运行在不同的机器上,彼此通过服务调用进行交互,前后台的业务流会经过很多个微服务的处理和传递,出现了异常如何快速定位是哪个环节出现了问题? ...

  3. sparse_softmax_cross_entropy_with_logits

    sparse_softmax_cross_entropy_with_logits 原创文章,请勿转载!!! 定义 sparse_softmax_cross_entropy_with_logits(_s ...

  4. 【原创】源码角度分析Android的消息机制系列(二)——ThreadLocal的工作过程

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 在上一篇文章中,我们已经提到了ThreadLocal,它并非线程,而是在线程中存储数据用的.数据存储以后,只能在指定的线程中获取到数据,对于其 ...

  5. 100、RESTful API

    本篇导航: RESTful RESTful API设计 基于django实现 基于Django Rest Framework框架实现 一.RESTful REST与技术无关,代表的是一种软件架构风格, ...

  6. python之闭包与装饰器

    python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...

  7. yum安装centos系统依赖库

    安装centos系统依赖库,安装软件过程中,经常需要的一些库,可以在编译安装软件前执行如下命令: 首先更新系统(这步可以不执行) yum -y update 这种更新是全部更新,但是有时一些软件不想更 ...

  8. BZOJ 4195: [Noi2015]程序自动分析 [并查集 离散化 | 种类并查集WA]

    题意: 给出若干相等和不等关系,判断是否可行 woc NOI考这么傻逼的题飞快打了一个种类并查集交上了然后爆零... 发现相等和不等看错了异或一下再叫woc90分 然后发现md$a \neq b, a ...

  9. 【STL】c++ priority_queue的使用方法

    最开始在项目文档看到priority_queue这个模板时,还以为是自己定义的呢,后来查了一下,原来这是STL中存在的一种优先队列. 1.最简单的使用方法 std::priority_queue< ...

  10. FastStone Capture的使用

    FastStone Capture的使用 FastStone Capture是一款精简而优秀的图像处理软件,在工作中会经常用到.我在本地安装了FastStone Capture 8.4版本 (提取码: ...