1 尽量不要往window上挂变量,少用闭包
2 避免频繁的触发垃圾回收机制

内存问题可以定义为下面这三类:

  • 内存泄漏 (Memory leak),它会导致页面的性能越来越差
  • 内存膨胀 (Memory bloat),它会导致页面的性能会一直很差
  • 频繁垃圾回收,它会导致页面出现延迟或者经常暂停

内存泄漏

在 JavaScript 中,造成内存泄漏 (Memory leak) 的主要原因是不再需要 (没有作用) 的内 存数据依然被其他对象引用着。

全局变量

  1. function foo() {
  2. //创建一个临时的temp_array
  3. temp_array = new Array(200000)
  4. /**
  5. * 使用temp_array
  6. */
  7. }
  8. =
  9. function foo() {
  10. //创建一个临时的temp_array
  11. this.temp_array = new Array(200000)
  12. /**
  13. * this.temp_array
  14. */
  15. }

在浏览器,默认情况下,this 是指向 window 对象的,而 window 对象是常驻内存 。

为了解决这个问题,我们可以在 JavaScript 文件头部加上use strict,使用严格模式避 免意外的全局变量,此时上例中的 this 指向 undefined。

闭包

  1. function foo(){
  2. var temp_object = new Object()
  3. temp_object.x = 1
  4. temp_object.y = 2
  5. temp_object.array = new Array(200000)
  6. /**
  7. * 使用temp_object
  8. */
  9. return function(){
  10. console.log(temp_object.x);
  11. }
  12. }

image.png

  1. function foo(){
  2. var temp_object = new Object()
  3. temp_object.x = 1
  4. temp_object.y = 2
  5. temp_object.array = new Array(200000)
  6. let closure = temp_object
  7. /**
  8. * 使用temp_object
  9. */
  10. return function(){
  11. console.log(closure);
  12. }
  13. }

DOM

由于 JavaScript 引用了 DOM 节点而造成的内存泄漏的问题,只有同时满足 DOM 树和 JavaScript 代码都不引用某个 DOM 节点,该节点才会被作为垃圾进行回收。 如果某个节点已从 DOM 树移除,但 JavaScript 仍然引用它,我们称此节点 为“detached ”。“detached ”节点是 DOM 内存泄漏的常见原因。

  1. let detachedTree
  2. function create() {
  3. var ul = document.createElement('ul');
  4. for (var i = 0; i < 100; i++) {
  5. var li = document.createElement('li');
  6. ul.appendChild(li);
  7. }
  8. detachedTree = ul;
  9. }
  10. create()

通过JavaScript 创建了一些 DOM 元素,有了这些内存中的 DOM 元素,当有需要的 时候,我们就快速地将这些 DOM 元素关联到 DOM 树上,一旦这些 DOM 元素从 DOM 上被移除后,它们并不会立即销毁,这主要是由于 JavaScript 代码中保留了这些元素的引 用,导致这些 DOM 元素依然会呆在内存中。所以在保存 DOM 元素引用的时候,我们需 要非常小心谨慎。

内存膨胀

内存膨胀和内存泄漏有一些差异,内存膨胀主要表现在程序员对内存管理的不科学,比如只 需要 50M 内存就可以搞定的,有些程序员却花费了 500M 内存。

内存膨胀和内存泄漏有一些差异,内存膨胀主要表现在程序员对内存管理的不科学,比如只 需要 50M 内存就可以搞定的,有些程序员却花费了 500M 内存。
image.png

我们可以看到,内存膨胀是快速增长,然后达到一个平衡的位置,而内存泄漏是内存一直在缓慢增长。
要避免内存膨胀,我们需要合理规划项目,充分利用缓存等技术来减轻项目中不必要的内存占用。

频繁的垃圾回收

  1. function strToArray(str) {
  2. let i = 0
  3. const len = str.length
  4. let arr = new Uint16Array(str.length)
  5. for (; i < len; ++i) {
  6. arr[i] = str.charCodeAt(i)
  7. }
  8. return arr;
  9. }
  10. function foo() {
  11. let i = 0
  12. let str = 'test V8 GC'
  13. while (i++ < 1e5) {
  14. strToArray(str);
  15. }
  16. }
  17. foo()

这段代码就会频繁创建临时变量,这种方式很快就会造成新生代内存内装满,从而频繁触发垃圾回收。为了解决频繁的垃圾回收的问题,你可以考虑将这些临时变量设置为全局变量。