一.垃圾收集

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. 根据URL下载图片至客户端、服务器实例

    1.保存至服务器 根据路径保存至项目所在服务器上. String imgUrl="";//图片地址 try { // 构造URL URL url = new URL(imgUrl) ...

  2. java从文件中读取json

    wangxiaoer.json里面存放了json数据 需要依赖common-io.jar

  3. 使用autoc js生成文章目录(侧边)导航栏

    介绍: autocjs 是一个专门用来生成文章目录(Table of Contents)导航的工具.autocjs 会查找文章指定区域中的所有 h1~h6 的标签,并自动分析文章的层次结构,生成文章的 ...

  4. java Object类是可以接收集合类型的

    废话不多说,上代码: package com.core.test; import java.util.ArrayList; import java.util.HashMap; import java. ...

  5. flask----flask-session

    一.flask-session flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,该组件则将支持session保存到多个地方 ...

  6. 浅谈计算机中的IO模型

    IO模型一共有5种: blocking IO #阻塞IO nonblocking IO #非阻塞IO IO myltiplexing #IO多路复用 signal driven IO #信号驱动IO ...

  7. springMvc+swagger整合例子

    Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模型紧密集成到服 ...

  8. php与web页面交互(二)

    一.获取表单数据 1.1 使用POST()方法提交表单  ---POST()方法可以没有限制地传递数据到服务器,所提交的数据在后台传输,用户在浏览器端是看不到这一过程的,安全性高,适用于发送保密数据和 ...

  9. 关于在jsp中的路径问题

    前言: jsp作为javaweb开发中常见的视图技术,我们平时在开发项目使用的过程中,经常会导入一些静态资源,比如css\js\jpg.png等图片格式的文件,这些文件的路径成了问题,经常会出现索引不 ...

  10. ConcurrenHashMap源码分析(二)

    本篇博客的目录: 一:put方法源码 二:get方法源码 三:rehash的过程 四:总结 一:put方法的源码 首先,我们来看一下segment内部类中put方法的源码,这个方法它是segment片 ...