3

今天总结下js的回收机制。

说起js的回收机制,一定要先说js的内存分配了。

内存分配

前端的同学们肯定知道,js的变量分为基本类型和引用类型。

  • 基本类型
    js的基本类型有String,Number,Boolean,Null,Undefined,这些变量在内存中占用固定的空间大小,声明之后会被分配到栈内存中,我们是按值访问的。
  • 引用类型
    js的引用类型的值大小是不固定的,需要通过引用来找到相应的值,在栈内存中会分配空间存放引用类型在堆内存中的地址,在堆内存中会存放对应的值。因为地址的大小是固定的,所以可以存在栈内存中,需要用到的时候,会到栈内存中先找到这个引用地址,然后再在堆中找到这个值。

为什么内存还要区分堆内存和栈内存呢?这里就要说到js的垃圾回收机制了。

为什么会有垃圾回收呢?当然是为了使程序运行时的内存最小啦。

当一个方法执行的时候,会有部分内存用来存方法中声明的变量,这些变量都被存在栈内存中,当方法结束的时候,这个栈内存中的变量(除了地址以外)都会被销毁。

但是当我们声明一个对象的时候,这个对象在其他地方也被引用了,这个对象的大小是不固定的,会被分配到堆内存中,随着方法的结束,这个堆内存也不会被销毁,因为其他地方还在引用(方法的传参等等),除非这个对象的引用为0,垃圾回收机制才会在核实之后销毁他,这里就牵扯到了垃圾回收中的引用计数,下面会讲到。

内存声明周期

内存声明周期:

  1. 分配你所需要的内存
  2. 使用分配到的内存读和写
  3. 不需要时将其释放

在js中,第三部分是自动完成的,因为js中有自动垃圾回收机制。在编写js时,不需要关心内存的使用问题,所需内存的分配和内存的释放都是自动完成的。

内存泄漏

什么情况下会内存泄漏?可以这么理解,就是有些代码本来应该要被回收的,但是没有被回收,所以一直占用着操作系统的内存,从而越积越多。一般的内存泄漏其实无关紧要,可怕的是内存泄漏引起的堆积,导致GC一直没办法使用所占用的内存给其他程序使用。

内存溢出

内存溢出就是程序向系统申请一定大小的内存,但是系统满足不了。

管理内存

处于安全的考虑,一般情况下系统给浏览器的内存会比给客户端的内存要少,即使浏览器内存泄漏了或者内存溢出了也不会让系统崩溃。内存限制的问题不仅会影响到给变量分配的内存,也会影响每个线程最多能执行的语句数量。

所以为了确保在有限的内存中可以让页面获得最好的性能,优化内存占用的最佳方式就是将其值设置为null来释放其引用。这个方法叫做解除引用,适用于全局变量和全局对象的属性,局部变量在离开执行环境之后就会自动被解除引用。

解除引用并不意味着马上回收该值所占用的内存,解除引用的真正作用是让值离开执行环境,让GC下次运行时自动将其回收。

垃圾回收

js的垃圾回收一般有两种,标记清除和引用计数。

标记清除

GC在运行时会给储存在内存中的所有变量加上标记,然后会去掉环境中的变量和被环境中的变量引用的变量的标记,在此之后被加上标记的变量被视为要删除的变量。然后GC完成内存清除。
标记清除会遵循以下几种情况:

  1. 在js中,全局变量和window对象会一直存在,不会被GC回收
  2. 递归所用到的所有方法和变量,不会被GC回收
  3. 闭包里用到的变量,不会被GC回收
  4. 所有被标记的,都被认为是垃圾,GC会启动其回收机制,释放内存。

引用计数

当对象被引用次数为0时,就被回收。潜在的一个问题是:循环引用时,两个对象都至少被引用了一次,将不能自动被回收。所以导致,我们常讲的内存泄露。


juan26
521 声望19 粉丝