今天总结下js的回收机制。
说起js的回收机制,一定要先说js的内存分配了。
内存分配
前端的同学们肯定知道,js的变量分为基本类型和引用类型。
- 基本类型
js的基本类型有String,Number,Boolean,Null,Undefined,这些变量在内存中占用固定的空间大小,声明之后会被分配到栈内存中,我们是按值访问的。 - 引用类型
js的引用类型的值大小是不固定的,需要通过引用来找到相应的值,在栈内存中会分配空间存放引用类型在堆内存中的地址,在堆内存中会存放对应的值。因为地址的大小是固定的,所以可以存在栈内存中,需要用到的时候,会到栈内存中先找到这个引用地址,然后再在堆中找到这个值。
为什么内存还要区分堆内存和栈内存呢?这里就要说到js的垃圾回收机制了。
为什么会有垃圾回收呢?当然是为了使程序运行时的内存最小啦。
当一个方法执行的时候,会有部分内存用来存方法中声明的变量,这些变量都被存在栈内存中,当方法结束的时候,这个栈内存中的变量(除了地址以外)都会被销毁。
但是当我们声明一个对象的时候,这个对象在其他地方也被引用了,这个对象的大小是不固定的,会被分配到堆内存中,随着方法的结束,这个堆内存也不会被销毁,因为其他地方还在引用(方法的传参等等),除非这个对象的引用为0,垃圾回收机制才会在核实之后销毁他,这里就牵扯到了垃圾回收中的引用计数,下面会讲到。
内存声明周期
内存声明周期:
- 分配你所需要的内存
- 使用分配到的内存读和写
- 不需要时将其释放
在js中,第三部分是自动完成的,因为js中有自动垃圾回收机制。在编写js时,不需要关心内存的使用问题,所需内存的分配和内存的释放都是自动完成的。
内存泄漏
什么情况下会内存泄漏?可以这么理解,就是有些代码本来应该要被回收的,但是没有被回收,所以一直占用着操作系统的内存,从而越积越多。一般的内存泄漏其实无关紧要,可怕的是内存泄漏引起的堆积,导致GC一直没办法使用所占用的内存给其他程序使用。
内存溢出
内存溢出就是程序向系统申请一定大小的内存,但是系统满足不了。
管理内存
处于安全的考虑,一般情况下系统给浏览器的内存会比给客户端的内存要少,即使浏览器内存泄漏了或者内存溢出了也不会让系统崩溃。内存限制的问题不仅会影响到给变量分配的内存,也会影响每个线程最多能执行的语句数量。
所以为了确保在有限的内存中可以让页面获得最好的性能,优化内存占用的最佳方式就是将其值设置为null来释放其引用。这个方法叫做解除引用,适用于全局变量和全局对象的属性,局部变量在离开执行环境之后就会自动被解除引用。
解除引用并不意味着马上回收该值所占用的内存,解除引用的真正作用是让值离开执行环境,让GC下次运行时自动将其回收。
垃圾回收
js的垃圾回收一般有两种,标记清除和引用计数。
标记清除
GC在运行时会给储存在内存中的所有变量加上标记,然后会去掉环境中的变量和被环境中的变量引用的变量的标记,在此之后被加上标记的变量被视为要删除的变量。然后GC完成内存清除。
标记清除会遵循以下几种情况:
- 在js中,全局变量和window对象会一直存在,不会被GC回收
- 递归所用到的所有方法和变量,不会被GC回收
- 闭包里用到的变量,不会被GC回收
- 所有被标记的,都被认为是垃圾,GC会启动其回收机制,释放内存。
引用计数
当对象被引用次数为0时,就被回收。潜在的一个问题是:循环引用时,两个对象都至少被引用了一次,将不能自动被回收。所以导致,我们常讲的内存泄露。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。