JS垃圾回收机制你知多少

垃圾回收机制

垃圾回收机制(Garbage Collention),简称GC。JS中内存的分配和回收都是自动完成的,在不使用的时候会被垃圾回收器自动回收。

内存的生命周期

JS环境中分配的内存,一般有如下生命周期:

  1. 内存分配: 当我们声明变量,对象,函数的时候,系统会自动为他们分配内存。
  2. 内存使用: 即读写内存,也就是使用变量,函数等。
  3. 内存回收: 使用完毕,由垃圾回收器自动回收不使用的内存
  • 全局变量一般不会回收(关闭页面回收)。
  • 一般情况下局部变量的值,不用了,会被自动回收。
js 复制代码
//为变量分配内存
const age = 18;
//为对象分配内存
const obj = {
  name: '小明',
  age: 18,
};
//为函数分配内存
function fn (){
    //局部变量的值,在函数调用完后,不使用就会被自动回收
    const age = 18;
    console.log(age);
}
fn()

内存泄漏

程序中分配的内存由于某种原因,程序未释放或无法是否叫内存泄漏。

常见的内存泄漏情况

意外的全局变量

js 复制代码
function foo(arg) {
    bar = "this is a hidden global variable";
}

另一种意外的全局变量可能由 this 创建:

js 复制代码
function foo() {
    this.variable = "potential accidental global";
}
// foo 调用自己,this 指向了全局对象(window)
foo();

上述使用严格模式,可以避免意外的全局变量。

定时器也常会造成内存泄露

js 复制代码
var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

如果id为Node的元素从DOM中移除,该定时器仍会存在,同时,因为回调函数中包含对someResource的引用,定时器外面的someResource也不会被释放。

闭包,维持函数内局部变量,使其得不到释放。

js 复制代码
function bindEvent() {
  var obj = document.createElement('XXX');
  var unused = function () {
    console.log(obj, '闭包内引用obj obj不会被释放');
  };
  obj = null; // 解决方法
}

没有清理对DOM元素的引用同样造成内存泄露

js 复制代码
const refA = document.getElementById('refA');
document.body.removeChild(refA); // dom删除了
console.log(refA, 'refA'); // 但是还存在引用能console出整个div 没有被回收
refA = null;
console.log(refA, 'refA'); // 解除引用

包括使用事件监听addEventListener监听的时候,在不监听的情况下使用removeEventListener取消对事件监听。

垃圾回收机制的实现方式

  • 标记清除
  • 引用计数

标记清除

JavaScript最常用的垃圾收回机制

当变量进入执行环境时,就标记这个变量为"进入环境"。进入环境的变量所占用的内存就不能释放,当变量离开环境时,则将其标记为"离开环境"。

垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。 随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存。

举个例子:

js 复制代码
var m = 0,n = 19 // 把 m,n,add() 标记为进入环境。
add(m, n) // 把 a, b, c标记为进入环境。
console.log(n) // a,b,c标记为离开环境,等待垃圾回收。
function add(a, b) {
  a++
  var c = a + b
  return c
}

引用计数

语言引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放

如果一个值不再需要了,引用数却不为0,垃圾回收机制无法释放这块内存,从而导致内存泄漏

js 复制代码
const arr = [1, 2, 3, 4];
console.log('hello world');

上面代码中,数组[1, 2, 3, 4]是一个值,会占用内存。变量arr是仅有的对这个值的引用,因此引用次数为1。尽管后面的代码没有用到arr,它还是会持续占用内存

如果需要这块内存被垃圾回收机制释放,只需要设置如下:

js 复制代码
arr = null

通过设置arrnull,就解除了对数组[1,2,3,4]的引用,引用次数变为 0,就被垃圾回收了

相关推荐
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax