JS的内存机制以及垃圾回收机制

JS内存空间分为栈、堆、池(一般归并到栈中)

基本数据类型string、number、boolean、null、undefined保存在栈中

复杂数据类型object保存在堆中

常量存放在池中

js中分配的内存的生命周期为:

内存分配->内存使用->内存回收

垃圾回收机制

js具有自动回收机制,垃圾收集器会按照固定的时间间隔周期性的执行。

两种方式:

(1)标记清除

 原理:当变量进入环境时,将这个变量定义为“进入环境”,将变量离开环境时,将其标记为“离开环境”,标记“离开环境”的就回收内存。

 工作流程:

  • 垃圾回收器。在运行的时候给存储在内存中的所有变量都加上标记。
  • 去掉环境中的变量以及被环境中的变量引用的变量(闭包)的标记。
  • 此时仍有标记的变量视为即将要删除的变量
  • 垃圾回收器完成内存清除的工作,销毁那些带标记的值并回收他们所占的内存空间。

(2)引用计数

工作原理:跟踪记录每个值被引用的次数

工作流程:

  • 声明一个变量并将一个引用类型值赋值给这个变量,这个引用类型值的引用次数就是1
  • 同一个引用类型值又被赋值给另一个变量,这个引用类型值的引用次数就加1
  • 当包含这个引用类型值的变量又取得了另一个值,这个引用类型值的引用次数就会减1
  • 当引用次数变为0时,说明没法访问这个值了。
  • 当垃圾回收器下一次运行时就会释放引用次数为0的值所占的内存空间。

引用计数的问题:循环引用 。循环引用指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用。请看下面这个例子

function problem(){     
    var objectA = new Object();
    var objectB = new Object(); 
 
    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA; 
} 

在这个例子中,objectA 和 objectB 通过各自的属性相互引用;也就是说,这两个对象的引用次数都是 2。

  在采用标记清除策略的实现中,由于函数执行之后,这两个对象都离开了作用域,因此这种相互引用不是个问题。但在采用引用计数策略的实现中,当函数执行完毕后,objectA 和 objectB 还将继续存在,因为它们的引用次数永远不会是 0。

哪些操作会造成内存泄漏?

内存泄漏指任何对象在不再拥有或不需要它之后依然存在,即这部分内存用完之后并没有返回到内存池。

(1)setTimeout第一个参数是字符串而不是函数的时候就会造成内存泄漏

(2)闭包

(3)控制台日志

(4)循环(两个对象彼此引用且彼此保留)

(5)全局变量

   如果你不断的创建全局变量,不管有没有用到他们,他们都将滞留在程序的整个执行过程中。

(6)事件监听器

  在页面中创建事件监听器,但是在页面跳转时,又忘记移除这些监听器,那么也可能导致内存泄漏。 

变量回收规则:

(1)全局变量不会被回收

(2)局部变量会被回收,也就是函数一旦运行完,函数内部的变量就会被销毁

(3)只要被另一个作用域引用就不会被销毁

原文地址:https://www.cnblogs.com/xiaoan0705/p/8663203.html