加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

中高级前端必须了解的JS中的内存管理

发布时间:2019-07-03 23:14:59 所属栏目:建站 来源:王爷科技
导读:前言 像C语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()用于分配内存和释放内存。 而对于JavaScript来说,会在创建变量(对象,字符串等)时分配内存,并且在不再使用它们时自动释放内存,这个自动释放内存的过程称为垃圾回收。 因为
副标题[/!--empirenews.page--]

 前言

像C语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()用于分配内存和释放内存。

中高级前端必须了解的JS中的内存管理

而对于JavaScript来说,会在创建变量(对象,字符串等)时分配内存,并且在不再使用它们时“自动”释放内存,这个自动释放内存的过程称为垃圾回收。

因为自动垃圾回收机制的存在,让大多Javascript开发者感觉他们可以不关心内存管理,所以会在一些情况下导致内存泄漏。

内存生命周期

中高级前端必须了解的JS中的内存管理

JS 环境中分配的内存有如下声明周期:

  1. 内存分配:当我们申明变量、函数、对象的时候,系统会自动为他们分配内存
  2. 内存使用:即读写内存,也就是使用变量、函数等
  3. 内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存

JS 的内存分配

为了不让程序员费心分配内存,JavaScript 在定义变量时就完成了内存分配。

  1. var n = 123; // 给数值变量分配内存 
  2. var s = "azerty"; // 给字符串分配内存 
  3. var o = { 
  4.  a: 1, 
  5.  b: null 
  6. }; // 给对象及其包含的值分配内存 
  7. // 给数组及其包含的值分配内存(就像对象一样) 
  8. var a = [1, null, "abra"];  
  9. function f(a){ 
  10.  return a + 2; 
  11. } // 给函数(可调用的对象)分配内存 
  12. // 函数表达式也能分配一个对象 
  13. someElement.addEventListener('click', function(){ 
  14.  someElement.style.backgroundColor = 'blue'; 
  15. }, false); 

有些函数调用结果是分配对象内存:

  1. var d = new Date(); // 分配一个 Date 对象 
  2. var e = document.createElement('div'); // 分配一个 DOM 元素 

有些方法分配新变量或者新对象:

  1. var s = "azerty"; 
  2. var s2 = s.substr(0, 3); // s2 是一个新的字符串 
  3. // 因为字符串是不变量, 
  4. // JavaScript 可能决定不分配内存, 
  5. // 只是存储了 [0-3] 的范围。 
  6. var a = ["ouais ouais", "nan nan"]; 
  7. var a2 = ["generation", "nan nan"]; 
  8. var a3 = a.concat(a2);  
  9. // 新数组有四个元素,是 a 连接 a2 的结果 

JS 的内存使用

使用值的过程实际上是对分配内存进行读取与写入的操作。

读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。

  1. var a = 10; // 分配内存 
  2. console.log(a); // 对内存的使用 

JS 的内存回收

JS 有自动垃圾回收机制,那么这个自动垃圾回收机制的原理是什么呢?

其实很简单,就是找出那些不再继续使用的值,然后释放其占用的内存。

大多数内存管理的问题都在这个阶段。

在这里最艰难的任务是找到不再需要使用的变量。

不再需要使用的变量也就是生命周期结束的变量,是局部变量,局部变量只在函数的执行过程中存在,

当函数运行结束,没有其他引用(闭包),那么该变量会被标记回收。

全局变量的生命周期直至浏览器卸载页面才会结束,也就是说全局变量不会被当成垃圾回收。

因为自动垃圾回收机制的存在,开发人员可以不关心也不注意内存释放的有关问题,但对无用内存的释放这件事是客观存在的。

不幸的是,即使不考虑垃圾回收对性能的影响,目前最新的垃圾回收算法,也无法智能回收所有的极端情况。

接下来我们来探究一下 JS 垃圾回收的机制。

垃圾回收

引用

垃圾回收算法主要依赖于引用的概念。

在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。

例如,一个Javascript对象具有对它原型的引用(隐式引用)和对它属性的引用(显式引用)。

在这里,“对象”的概念不仅特指 JavaScript 对象,还包括函数作用域(或者全局词法作用域)。

引用计数垃圾收集

这是最初级的垃圾回收算法。

引用计数算法定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。

如果没有其他对象指向它了,说明该对象已经不再需了。

  1. var o = {  
  2.  a: { 
  3.  b:2 
  4.  } 
  5. };  
  6. // 两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量o 
  7. // 很显然,没有一个可以被垃圾收集 
  8. var o2 = o; // o2变量是第二个对“这个对象”的引用 
  9. o = 1; // 现在,“这个对象”的原始引用o被o2替换了 
  10. var oa = o2.a; // 引用“这个对象”的a属性 
  11. // 现在,“这个对象”有两个引用了,一个是o2,一个是oa 
  12. o2 = "yo"; // 最初的对象现在已经是零引用了 
  13.  // 他可以被垃圾回收了 
  14.  // 然而它的属性a的对象还在被oa引用,所以还不能回收 
  15. oa = null; // a属性的那个对象现在也是零引用了 
  16.  // 它可以被垃圾回收了 

由上面可以看出,引用计数算法是个简单有效的算法。但它却存在一个致命的问题:循环引用。

如果两个对象相互引用,尽管他们已不再使用,垃圾回收不会进行回收,导致内存泄露。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读