C、C++语言需要手动管理内存的分配与释放(常用方法:malloc(), calloc(), realloc()和free()等)。而JavaScript与Java、C#相似,内置了垃圾回收器,能自动管理内存的分配与释放。

内存生命周期:

  1. 分配内存
  2. 使用分配的内存(读与写操作)
  3. 当应用程序不再需要时,释放掉已分配的内存

虽然垃圾回收器能能自动管理内存分配、释放,但并不意味着开发者不再需要关注内存管理。因为一些不好的编码会导致内存泄露,即应用程序不再需要的内存没有被释放掉。因此了解内存管理是很重要的。

Javascript中的内存分配

当声明变量时,JavaScript会自动为变量分配内存

var numberVar = 100; //为整数分配内存
var stringVar = 'node simplified'; // 为字符串分配内存
var objectVar = {a: 1}; // 为对象分配内存
var a = [1, null, 'abra']; // 为数组分配内存
function f(a) {
return a + 2;
} // 为函数分配内存

GC(Garbage collection)

垃圾回收是追踪并释放应用程序不再使用的内存过程。垃圾回收器通过算法来实现追踪应用程序不再使用的内存。主要涉及的垃圾回收算法如下:

  • Reference-counting garbage collection(引用计数)
  • Mark-and-sweep algorithm(标记清除)

Reference-counting garbage collection(引用计数)

引用计数算法是一种最基础的垃圾回收算法,当一个对象的引用数为零时,会被自动回收。该算法将一个对象的引用数为0时视为应用程序不再需要的内存。

!function (){
var o1 = {a: {b: 2}},// 两个对象被创建。假如分别用A:{a: {b: 2}},B:{b: 2}表示,对象B被对象A的属性a引用,对象A被赋值给变量o1。A和B的引用数都为1,因此不能被回收。
o2 = o1; // 将对象A赋给变量o2。此时A引用数为2,B引用数1。
o1 = 1;// 将变量o1对对象A引用切断。此时A引用数为1,B引用数1。
var oa = o2.a; // 将对象B赋值给变量oa。此时A引用数为1,B引用数2。
o2 = 'foo'; // 将变量o2对对象A引用切断。此时A引用数为0,B引用数1。因为对象A的a属性被变量oa引用,因此对象A不能被释放。
oa = null; // 将变量oa对对象B引用切断。此时A引用数为0,B引用数0。A与B会被回收。
}()

引用计数的限制:循环引用

循环引用存在一个限制。如下实例,两个对象相互引用,形成一个循环引用。正常情况下,当函数执行完后,对应的内存会被释放掉。而引用计数算法会将循环引用对象的引用数都视为至少为1,因此不能被回收。

function f() {
var o = {};
var o2 = {};
o.a = o2; // o references o2
o2.a = o; // o2 references o return 'azerty';
} f();

常见问题

IE6-7的DOM对象是基于计数引用算法进行垃圾回收的。而循环引用通常会导致内存泄露:

var div;
window.onload = function() {
div = document.getElementById('myDivElement');
div.circularReference = div;
div.lotsOfData = new Array(10000).join('*');
};

如上述实例,DOM元素div通过自身的“circularReference”属性循环引用自己。如果没有显式将该属性删除或设为null,计数引用垃圾回收器会始终持有至少一个引用。即使DOM元素从DOM树种移除,DOM元素的内存会一直存在。如果DOM元素持有一些数据(如实例中“lotsData”属性),该数据对应的内存也无法被释放。了解更多参考--->IE<8循环引用导致的内存泄露

Mark-and-sweep algorithm(标记清除)

该算法将“对象不再需要”的定义简化为“对象不可到达”。 这个算法假设有一组被称为roots的对象(在JavaScript中,root就是全局对象)。垃圾回收器会定期地从这些roots开始,查找所有从根开始引用的对象,然后再查找这些对象引用的对象……。从roots开始,垃圾回收器会查找所有可到达对象,并回收不可到达的对象。

为了确定对象是否需要,该算法要确定对象是否可到达。由如下步骤组成:

  1. 垃圾回收器会创建一组roots,roots通常是持有引用的全局变量。在JavaScript中,window对象就可作为root的全局变量。
  2. 垃圾回收器会检查所有的roots并标记为活跃状态。然后递归遍历所有的子变量。只要从root不能到达的都被标记为垃圾。
  3. 所有没有被标记为活跃状态的内存块都被视为垃圾。垃圾回收器就可以释放这部分内存并把释放的内存返回给操作系统。

这个算法比引用计数算法更优,因为对于引用计数算法“零引用的对象”总是不可到达的,但反之则不一定,如循环引用。而标记清除算法不存在循环引用的问题。

截至2012年,所有现代浏览器都内置了标记清除垃圾回收器。在过去几年里所有对JavaScript垃圾回收算法的改进(generational/incremental/concurrent/parallel garbage collection)都是基于标记清除算法来实现的,但并没有改变标记清除算法本身和它对“对象不再需要”定义的简化。

循环引用不再是问题

前面循环引用的实例中,在函数执行完后,两个对象不再被全局对象可访问的对象引用。因此这两个对象被垃圾回收器标记为不可到达,接着被回收掉。 

限制:需要明确无法到达的对象

对于这个限制,实践中很少遇见,所以开发者不太会去关心垃圾回收机制。

参考文章:

原文地址: https://github.com/cucygh/js-leakage-patterns/blob/master/JavaScript%E5%86%85%E5%AD%98%E9%82%A3%E7%82%B9%E4%BA%8B/JavaScript%E5%86%85%E5%AD%98%E9%82%A3%E7%82%B9%E4%BA%8B.md

JavaScript中的内存释放的更多相关文章

  1. JavaScript 中对内存的一些了解

    在使用JavaScript进行开发的过程中,了解JavaScript内存机制有助于开发人员能够清晰的认识到自己写的代码在执行的过程中发生过什么,也能够提高项目的代码质量.其实关于内存的文章也有很多,写 ...

  2. JavaScript中的内存泄漏以及如何处理

    随着现在的编程语言功能越来越成熟.复杂,内存管理也容易被大家忽略.本文将会讨论JavaScript中的内存泄漏以及如何处理,方便大家在使用JavaScript编码时,更好的应对内存泄漏带来的问题. 概 ...

  3. javascript中的内存管理和垃圾回收

    前面的话 不管什么程序语言,内存生命周期基本是一致的:首先,分配需要的内存:然后,使用分配到的内存:最后,释放其内存.而对于第三个步骤,何时释放内存及释放哪些变量的内存,则需要使用垃圾回收机制.本文将 ...

  4. Javascript中的内存泄漏

    最新博客站点:欢迎来访 一.内存泄漏        由于某些原因不再需要的内存没有被操作系统或则空闲内存池回收.编程语言中有多种管理内存的方式.这些方式从不同程度上会减少内存泄漏的几率,高级语言嵌入了 ...

  5. javascript中的内存管理

    目录 简介 内存生命周期 JS中的垃圾回收器 引用计数垃圾回收算法 Mark-and-sweep回收算法 调试内存问题 闭包Closures中的内存泄露 javascript中的内存管理 简介 在c语 ...

  6. JavaScript 中的内存泄漏

    JavaScript 中的内存泄漏 JavaScript 是一种垃圾收集式语言,这就是说,内存是根据对象的创建分配给该对象的,并会在没有对该对象的引用时由浏览器收回.JavaScript 的垃圾收集机 ...

  7. 浅谈JavaScript中的内存管理

    一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...

  8. JavaScript 中的内存和性能、模拟事件(读书笔记思维导图)

    由于事件处理程序可以为现代 Web 应用程序提供交互能力,因此许多开发人员会不分青红皂白地向页面中添加大量的处理程序.在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体 ...

  9. JavaScript中的内存溢出与内存泄漏

    内存溢出 是一种程序运行出现的错误: 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误 var obj = {} for (var i = 0; i < 100000; i++) ...

随机推荐

  1. FFT(快速傅里叶变换) 模板

    洛谷 P3803 [模板]多项式乘法(FFT)传送门 存个板子,完全弄懂之后找机会再写个详解. #include<cstdio> #include<cmath> struct ...

  2. [LC] 48. Rotate Image

    You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). ...

  3. JavaScript小数转百分比

    在浏览器的控制台操作0.28*100会得到28.000000000000004这样一个不太精确的值 进行转换 toPercent(point){ let str = Number(point * 10 ...

  4. mysql 子查询 合并查询

    4.1带In 关键字的子查询 一个查询语句的条件可能落在另一个SELECT 语句的查询结果中. SELECT * FROM t_book WHERE booktypeId IN (SELECT id ...

  5. JVM常见问题分析

    JVM常见问题分析 启动,并且去查看日志 ./startup.sh && tail -f ../logs/catalina.out 常见有有以下几个问题: 1.java.lang.Ou ...

  6. TCP\IP协议簇-分层模型

    OSI 模型   数据单元 层 功能 主机层 Data(数据) 7. 应用层 网络进程到应用程序. 6. 表示层 数据表示形式,加密和解密,把机器相关的数据转换成独立于机器的数据. 5. 会话层 主机 ...

  7. Luogu_2876_[USACO07JAN]解决问题Problem Solving

    题目描述 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地说,他们有\(P(1 \leq P \leq 300)\)道题目要做. 他们还离开了农场并且象普通人一 ...

  8. 【转载】[基础知识]【网络编程】TCP/IP

    转自http://mc.dfrobot.com.cn/forum.php?mod=viewthread&tid=27043 [基础知识][网络编程]TCP/IP iooops  胖友们楼主我又 ...

  9. mysql表关系

    表与表之间的关系 """ 把所有数据都存放于一张表的弊端 1.组织结构不清晰 2.浪费硬盘空间 3.扩展性极差 """ # 上述的弊端产生原 ...

  10. react-native保存图片Android实现方法

    /图片的路径格式为远程请求, 例如:'http://xxx:8080/image.jpg' import { Platform, PermissionsAndroid, NativeModules } ...