【JS】—垃圾回收机制

2023-09-20 10:19:26

一、指令材料

1.定义

JavaScript(JS)的垃圾回收机制是一种自动管理内存的过程,它有助于释放不再使用的内存,以避免内存泄漏和提高程序的性能。
JavaScript的垃圾回收机制是一种自动管理内存的方式,以确保不再被引用的对象可以被垃圾回收,释放内存。

2.分类

2-1. 引用计数算法

引用计数算法通过跟踪每个对象被引用的次数来决定何时回收内存。当一个对象的引用计数为零时,它就会被垃圾回收.

2-2. 循环引用

循环引用是一种特殊情况,其中两个或多个对象互相引用,导致它们的引用计数不会降为零。这时,垃圾回收需要使用更复杂的算法来检测并处理循环引用。

2-3. 标记清除算法

标记清除算法通过标记所有从根对象(通常是全局对象)可达的对象,然后清除未标记的对象来回收内存。

二、 限定条件

JavaScript的垃圾回收机制主要涉及对象的管理,而基本数据类型通常不涉及垃圾回收,因为它们是简单的值,而不是对象。JavaScript的垃圾回收机制更关注于复杂数据类型,如对象和数组。

  1. 数字(Number): 基本数据类型的数字是不需要垃圾回收的,因为它们只是简单的数值,没有引用其他对象或数据。
let x = 42; // 基本数据类型的数字
  1. 字符串(String): 基本数据类型的字符串也不需要垃圾回收,因为它们是不可变的,没有内部引用需要跟踪。
 let name = "John"; // 基本数据类型的字符串
  1. 布尔值(Boolean): 基本数据类型的布尔值也不需要垃圾回收,因为它们只表示真或假。
let isLogged = true; // 基本数据类型的布尔值
  1. 空值(null)和未定义(undefined): 这些特殊的基本数据类型表示缺少值或未定义的值。它们也不需要垃圾回收。
let emptyValue = null; // 空值
let undefinedValue; // 未定义

三、做练习题

1. 引用计数算法

// 把 {name: ‘John’} 代指A
//  A 对象被obj1 引用1次,A 引用计数=1次
let obj1 = { name: 'John' };
//  A 对象被obj2 引用1次,A 引用计数=2次
let obj2 = obj1; 


// 解除obj1 的引用对象A, A 引用计数 = 1 次
obj1 = null;
// 解除obj2 的引用对象A, A 引用计数 = 0 次
obj2 = null; 

// 对象A 没有被任何变量引用,将被垃圾回收机制回收

总结归纳:

  1. 引用计数是指一个对象的堆内存空间被引用了几次
  2. 通过=号,给变量赋值对象,引用增加
  3. 通过=号,给变量赋值为null, 解除对象的引用

2-1. 循环引用

function createCircularReference() {
  // 把 {} 代指 A, A 被obj1 引用1次, A的引用计数 = 1次
  let obj1 = {}; // 
  // 把 {} 代指 B, B 被obj1 引用1次, B的引用计数 = 1次
  let obj2 = {}; // 
  // B 被 obj1.circularRef 引用1次, B的引用计数 = 2次
  obj1.circularRef = obj2; 
  // A 被 obj2.circularRef 引用1次, A的引用计数 = 2次
  obj2.circularRef = obj1; 
  // 这里有一个循环引用,即obj1和obj2互相引用
}

// 当函数执行完毕后,obj1和obj2都会离开作用域,
// 但由于它们互相引用,它们的引用计数不会降为零,
// 垃圾回收需要检测和处理这种循环引用```

总结归纳:

  1. 循环引用,引用计数不会降为零
  2. 循环引用是通过两个对象的属性,相互赋值另外一个对象,实现相互引用

1和2-1对比归纳:

  1. 大括号中无论是否有值,都会开辟新的内存空间
  2. 绑定引用和解除引用都使用=号,

2-2. 手动解除引用

你可以通过将循环引用的其中一个对象设置为null来手动解除引用。这将打破循环引用,允许垃圾回收器正确地识别这些对象并释放它们。

// 循环引用
const obj1 = {};
const obj2 = {};
obj1.ref = obj2;
obj2.ref = obj1;

// 手动解除引用obj1.ref = null;
obj2.ref = null;

总结归纳:

  1. 绑定引用和解除引用的属性或对象,要保持一致性

2-3. WeakMap和WeakSet 解除引用

JavaScript提供了WeakMap和WeakSet数据结构,它们允许你存储弱引用(不会阻止垃圾回收的引用)。这些数据结构不会阻止对象被回收,因此可以用于解决循环引用问题。当你不再需要这些引用时,它们会自动被垃圾回收

const obj1 = {};
const obj2 = {};

const weakMap = new WeakMap();
weakMap.set(obj1, obj2);
weakMap.set(obj2, obj1);

// 当不再需要循环引用时,它们会被自动释放

总结归纳:

  1. 使用 weakMap方法,内存变成弱引用,不受引用计数的影响,自动被回收站回收。

3. 标记清除算法

标记清除算法通过标记所有从根对象(通常是全局对象)可达的对象,然后清除未标记的对象来回收内存。

// 标记所有能够从根对象访问到的对象,通常包括全局变量、当前调用栈中的变量等。标记的对象会被标记为“活动”
function createUser() {
  let user = {
    name: 'Alice',
    age: 30  
  };
  return user;
}
// 遍历:垃圾回收器遍历整个对象图,标记所有与活动对象相互引用的对象,以确保不会因为被引用而被清除。
let userData = createUser(); 
// 现在userData不再引用对象
userData = null; 

// 当userData变为null后,活动对象被解除引用
// 垃圾回收会将这个对象createUser()清除

总结归纳:

  1. 标记全局变量下对象,为活动对象
  2. 遍历查询出,哪些活动对象被引用,防止被垃圾回收

总结规律:

  1. 引用计数是指一个对象的堆内存空间被引用了几次
  2. 通过=号,给变量赋值对象,引用增加
  3. 通过=号,给变量赋值为null, 解除对象的引用
  4. 循环引用是通过两个对象的属性,相互赋值另外一个对象,实现相互引用
  5. 循环引用,引用计数不会降为零
  6. 手动解除引用,通过把基本数据类型赋值给变量,解除变量和对象的引用关系
  7. 对象弱引用,使用weakMap和WeakSet方法实现两个对象的弱引用,使用完成后允许垃圾回收
  8. 标记全局变量下对象,为活动对象
  9. 遍历查询出,哪些活动对象被引用,防止被垃圾回收

四、建立新学的知识与旧知识之间的关联

1. js的垃圾回收机制和 delete 删除对象的属性

  1. js的垃圾回收机制,把代码中没有被引用的对象,自动清除该对象所占用的内存空间;delete 删除对象的属性
  2. 两者之间的区别
  • 一个清除未被引用对象的内存空间;一个是删除对象的属性
  • 一个自动清除;一个是手动删除
  • 两者的本质:都是清除掉不需要的东西,达成某个功能
// {name:'xiao'} 被obj1 引用1次,{name:'xiao'} 的引用计数 = 1
let obj1 = {name:'xiao'} 
// 解除 ob1 和 {name:'xiao'} 引用关系, {name:'xiao'}的引用计数 = 0, {name:'xiao'} 将被垃圾回收
obj1 = null
let params = {
	id: 123,
	name: 'xiao'
	phone: '123456789'
}
// 业务需求是,新增时,删除id
if (state === 'add'){
	delete params.id
}

2. 引用计数算法(暂时想不到与那个旧知识关联,日后补充)

3. 标记清除算法(暂时想不到与那个旧知识关联,日后补充)

五、 转换表述

1. js的垃圾回收机制

垃圾回收机制,就是我们平时去吃火锅时,每一盘菜就是就是一个正在被使用的内存,当菜被吃完后,服务员会把空盘子自动拿走,以保证桌面整洁和提高用户体验。
在这里插入图片描述

2. 引用计数算法

引用计数算法就像我们吃完火锅,一包卫生纸盒,给每个人都发一张,直到卫生纸都发完了,只剩下空纸盒,它就会被垃圾回收。引用计数的本质是,该物品(或对象)对某人或事物,还有没有它的价值。
在这里插入图片描述

3. 循环引用

循环引用就是两个正在热恋的年轻人,两个人相互吸引,都离不开对方,脑海中无时无刻在想着对方,所以引用计数永远不会为零,直到他们分手时,他们之间的引用计数才会变成0
在这里插入图片描述

4. 标记清除算法

标记清除算法就是书桌上有很多东西,比如零食、玩具、书本、笔,然后现在妈妈让你写作业,把无关的东西收拾起来,零食、玩具就会被收拾起来(垃圾回收)。
标记清除算法的本质,把没有使用的东西清除掉。

在这里插入图片描述

更多推荐

c++多态

目录多态的概念多态实现计算器案例c++如何实现动态绑定纯虚函数和抽象类纯虚函数和多继承虚析构函数虚析构函数作用纯虚析构函数重载重定义重写多态的概念多态:一种接口,多种形态静态多态:如果函数的调用,在编译阶段就可以确定函数的调用地址,并产生代码,就是静态多态(编译时多态)动态多态:调用地址不能编译不能在编译期间确定,而需

电脑摄像头录像软件推荐,总有一款适合你!

“有没有好用的电脑摄像头录像软件推荐呀,最近因为工作原因,需要用到电脑摄像头录像,但是因为不会操作,导致进度一直跟不上,想问问大家,帮忙推荐一款好用的电脑摄像头录像软件!”电脑摄像头是我们在日常工作和娱乐中不可或缺的工具,它可以用于视频通话、拍摄照片和录制视频等多种用途。然而,很多人对于如何使用电脑摄像头进行录像并不是

【HTTP】Cookie 和 Session 详解

Cookie和Session一.Cookie1.什么是Cookie2.Cookie的作用3.Cookie的组成4.Cookie的组织形式5.Cookie的传输6.如何提高Cookie的安全性7.Cookie类二.Session1.理解会话机制(Session)2.Sessoin的组织形式3.HttpSession类三.

单例模式-饿汉模式、懒汉模式

单例模式,是设计模式的一种。在计算机这个圈子中,大佬们针对一些典型的场景,给出了一些典型的解决方案。目录单例模式饿汉模式懒汉模式线程安全单例模式单例模式又可以理解为是单个实例(对象)在有些场景中,有特定的类,只能创建出一个实例,不应该创建多个实例。使用了单例模式以后,此时想要创建多个实例就变得很困难~Java中的单例模

算法通过村第八关-树(深度优先)青铜笔记|经典算法题目

文章目录前言1.二叉树里面的双指针1.1判断两棵树是否相同1.2对称二叉树1.3合并二叉树2.路径专题2.1二叉树的所有路径2.2路径总和3.翻转的妙用总结前言提示:人类的底里是悲伤,我们都在用厚重的颜料,覆盖那些粗糙的线稿。--张皓宸《抬头看二十九次月亮》前面的练习才是开始,这理才是真正的进入算法的门槛,来迎接下一波

ELK 企业级日志分析系统

----------------------ELK概述----------------------------------------1、ELK简介ELK平台是一套完整的日志集中处理解决方案,将ElasticSearch、Logstash和Kiabana三个开源工具配合使用,完成更强大的用户对日志的查询、排序、统计需求

[刷题记录]牛客面试笔刷TOP101(二)

(一)传送门:[刷题记录]牛客面试笔刷TOP101(一)_HY_PIGIE的博客-CSDN博客目录1.合并二叉树2.二叉树的镜像3.判断是否为二叉搜索树4.判断是不是完全二叉树1.合并二叉树合并二叉树_牛客题霸_牛客网(nowcoder.com)思路:在后序遍历的基础上进行,两颗二叉树可能会有位置有空缺的情况.在一个子

Python基础学习笔记1(AI Studio)

地址:飞桨AIStudio星河社区-人工智能学习与实训社区课程地址:飞桨AIStudio星河社区-人工智能学习与实训社区课程地址:飞桨AIStudio星河社区-人工智能学习与实训社区课程地址:飞桨AIStudio星河社区-人工智能学习与实训社区AIStudio的Notebook项目的基本操作项目启停执行和调试多文件代码

JavaScript面试题整理(一)

数据类型篇1、JavaScript有哪些数据类型,它们的区别是什么?基本数据类型:number、string、boolean、undefined、NaN、BigInt、Symbol引入数据类型:ObjectNaN是JS中的特殊值,表示非数字,NaN不是数字,但是它的数据类型是数字,它不等于任何值,包括自身,在布尔运算时

ELK企业级日志分析系统

ELK概述为什么要使用ELK日志主要包括系统日志、应用程序日志和安全日志。系统运维和开发人员可以通过日志了解服务器软硬件信息、检查配置过程中的错误及错误发生的原因。经常分析日志可以了解服务器的负荷,性能安全性,从而及时采取措施纠正错误。往往单台机器的日志我们使用grep、awk等工具就能基本实现简单分析,但是当日志被分

如何进行网络编程?

网络编程是计算机科学领域中的一个重要主题,允许计算机之间通过网络进行通信和数据交换。在C语言中,网络编程通常涉及使用套接字(socket)API来创建、连接、发送和接收网络数据。本文将介绍如何进行基本的网络编程,包括创建套接字、建立连接、发送和接收数据,以帮助C语言初学者入门这一领域。1.套接字(Socket)简介套接

热文推荐