JavaScript:内存与内存泄露

JS变量具体是存放在哪里呢?

  • 基本数据类型保存在栈内存中
  • 引用数据类型保存在堆内存中
  • 基本数据类型6种: Undefined、Null、Boolean、Number、String、Symbol, 由于他们在内存中分别占有固定大小的空间, 通过按值来访问.
  • 引用数据类型: 也就是Object对象, 它的存储分为访问地址和实际存放的地方; 访问地址是存储在栈中的, 当查询引用类型变量的时候, 会先从栈中读取内存地址(也就是访问地址), 然后再通过地址找到堆中的值.因此, 这种我们也把它叫为引用访问.

栈数据结构

特点:后进先出(LIFO)的结构

这里所说的进栈和出栈不是指赋值算进, 使用算出. 而是指赋值算进, 被清理算出, 而且位于同一函数作用域下的变量, 应该是在栈的同一层.

所谓的变量存储于栈内存中的栈,传统意义上说指的是由内存自动创建分配的空间,例如函数的参数值与局部变量,只是其操作方式类似于栈操作,所以叫栈内存。

比如函数调用其实就相当于栈的形式:

scss 复制代码
function fn1() {
	console.log(1)
  fn2()
}
function fn2() {
	console.log(2)
	fn3()
}
function fn3() {
	console.log(3)
}
fn1()

如上, 声明的顺序是1, 2, 3 , 但是释放的顺序是为3, 2, 1 .

这里释放按照这个顺序是因为 3最先执行完, 所以最先被释放.

堆数据结构

一种树状结构。好比 JSON 格式中的数据,你有 key,我有对应的 value, 就立马返给你。

因为我们知道JSON格式的存储是无序的, 所以没有先后顺序, 所以它是一种绝对公平的数据结构.

队列数据结构

队列数据结构不同于堆, 队列是一种先进先出(FIFO)的数据结构.它也是事件循环(Event Loop)的基础结构。最先进入队列的任务最先出来, 类似于你排队买票, 排在前面的人先买.

内存管理

内存空间也是有属于自己的生命周期, 它主要分为三个阶段:

  1. 分配你所需的内存;
  2. 使用分配到的内存(读、写);
  3. 不需要的时候将其释放、归还.

JS有自动垃圾收集机制, 听着这个机制的名字我想大家就知道它是做什么的了, 没错就是字面意思, 它会找出那些不再继续使用的值,然后释放其占用的内存。垃圾收集器会每隔固定的时间段就执行一次释放操作。

在自动垃圾收集机制中, 最常用的就是通过标记清除的算法来找到哪些对象不再继续使用.

此外 在局部作用域中, 当函数执行完毕了之后, 局部变量就没有存在下去的必要了, 此时垃圾收集器知道这类变量是需要回收的, 所以很容易判断.但是全局变量什么时候需要释放内存空间则很难判断,因此在我们的开发中,原则上应该避免使用全局变量。

局部变量和局部变量如何销毁的

局部变量的销毁

全局变量的销毁

JavaScript 引擎

JavaScript 引擎将 JavaScript 编译成本地机器代码并执行。每个主要的浏览器都开发了自己的 JS 引擎。谷歌的 Chrome 使用 V8,Safari 使用 JavaScriptCore,Firefox 使用 SpiderMonkey。

垃圾回收

垃圾回收的思想很简单,有些数据被使用之后可能不再需要了,这就产生了垃圾数据,我们需要回收这些垃圾数据,释放内存空间。

通常情况下,垃圾回收策略分为

  • 手动回收
  • 自动回收

内存泄露

垃圾回收器的回收范围一般小于垃圾的范围。

因为有些东西,垃圾回收器不知道我们需要不需要

内存泄露是指一块内存空间不再被使用,但是没有被释放。在JavaScript中,内存泄露通常是因为一些对象被长时间引用,导致垃圾回收器无法回收这些对象。 可以通过chrome的Performance工具来检测内存泄露,查看内存的变化情况,找出内存泄露的原因。

内存泄露的本质

不可达的对象未释放:程序中存在一些不再使用的对象,但由于被引用(或误引用),垃圾回收器(GC)无法识别它们为"可回收对象",从而导致内存无法释放。(判断这个东西要不要用,用就保留,不用要清除或释放比如某个变量置空)

资源得不到回收:这些资源可能包括未清理的事件监听器、定时器、闭包中未释放的变量等。

清除策略:标记清除算法

常见的内存泄露

  1. 意外的全局变量
  • 未声明的变量
  • 使用this创建的变量
  • 被遗忘的计时器或回调函数
  • 闭包

内存泄露的识别方法

Chrome 浏览器查看内存占用,按照以下步骤操作。

  1. 在网页上右键, 点击"检查"打开控制台(Mac快捷键option+command+i);
  2. 选择Performance面板(很多教材中用的是Timeline面板, 不知道是不是版本的原因);
  3. 勾选Memory, 然后点击左上角的小黑点Record开始录制;
  4. 点击弹窗中的Stop结束录制, 面板上就会显示这段时间的内存占用情况。

根据这条蓝线可以初步判断是否存在内存泄漏:如果这条蓝线持续上升,那很可能存在内存泄漏。 然而,实际上这种说法有些偏颇。JS堆内存占用率的增长并不一定意味着内存泄漏,只能表明有许多未释放的内存存在。要确定这些内存是否真正被使用,或者确实存在内存泄漏,还需要进一步的排查和分析。

对比两次内存快照,查看内存中的对象和数据是否有明显的增加或者未释放的情况。特别要注意查看是否有多余的对象被引用、未释放的事件监听器、定时器等情况。

根据对比结果,定位可能存在内存泄漏的代码段,并进行优化和改进。

相关推荐
Excel_VBA表格จุ๊บ1 小时前
wps宏js接入AI功能和接入翻译功能
javascript·wps·js宏
豪宇刘2 小时前
JavaScript 延迟加载的方法
开发语言·javascript
摇光933 小时前
js迭代器模式
开发语言·javascript·迭代器模式
anyup_前端梦工厂5 小时前
了解 ES6 的变量特性:Var、Let、Const
开发语言·javascript·ecmascript
每天都要进步哦5 小时前
Node.js中的fs模块:文件与目录操作(写入、读取、复制、移动、删除、重命名等)
前端·javascript·node.js
布兰妮甜5 小时前
Three.js 渲染技术:打造逼真3D体验的幕后功臣
javascript·3d·three.js·幕后
仿生狮子6 小时前
CSS Layer、Tailwind 和 sass 如何共存?
javascript·css·vue.js
在路上`6 小时前
vue3使用AntV X6 (图可视化引擎)历程[二]
javascript·vue.js
我命由我123456 小时前
CesiumJS 案例 P34:场景视图(3D 视图、2D 视图)
前端·javascript·3d·前端框架·html·html5·js
SunnyRivers7 小时前
JavaScript动态渲染页面爬取之Selenium
javascript·selenium