细读 JS | 浅谈内存泄露、内存溢出

简介: 细读 JS | 浅谈内存泄露、内存溢出

前言


讲真,这两个概念很容易被混为一谈。


正文


一、内存


在 JavaScript 中,没有像 C 语言等提供有内存管理接口,JavaScript 是在创建变量时自动进行分配内存,并且在不使用它们时“自动”释放。释放的过程被称为“垃圾回收”。


这个“自动”就是混乱的根源,并让 JavaScript 开发者错误地认为他们可以不用关心内存管理。


内存的生命周期


不管什么程序语言,内存的生命周期基本是一致的:

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

所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像 JavaScript 这些高级语言中,大部分都是隐含的。


内存管理的难题


大多数内存管理的问题都在“当内存不需要使用时释放”这个阶段。最困难的就是如何界定并找到“哪些被分配的内存确实不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。

高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)


垃圾回收(Garbage Collection,GC)


由于一些内存“不再需要”的问题无法判定,因此,垃圾回收实现只能有限制的解决一般问题。

  • 引用计数算法
    最初的垃圾回收算法,它把“对象是否不再需要”简化为“对象有没有其他对象引用到它”。如果没有引用指向改对象(零引用),对象将被垃圾回收机制回收。但是这个算法有个限制,无法处理循环引用的情况。
    关于“引用”的概念,一个对象如果有访问另一个对象的权限(显式或隐式),叫做一个对象引用另一个对象。
  • 标记清除算法
    这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。
    这个算法假定设置一个叫做根对象(在 Javascript 里是 globalThis 对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。
    它解决了早期算法无法处理循环引用的问题,但还是有一个限制:那些无法从根对象查询到的对象都将被清除(实际中很少会碰到这种情况)。
    从 2012 年起,所有现代浏览器都使用了标记清除垃圾回收算法。所有对 JavaScript 垃圾回收算法的改进都是基于标记-清除算法的改进,并没有改进标记-清除算法本身和它对“对象是否不再需要”的简化定义。


所以,通常我们不会在全局作用域下进行过多的变量或函数声明,更推荐将它们放在立即执行函数表达式(IIFE)内进行声明。否则它们将无法被垃圾回收,即在程序的生命周期内一直存在。


这一小节提到的“对象”,不仅特指 JavaScript 对象,还包括函数作用域、全局作用域。


二、内存泄露、溢出


区别


这两个概念是存在区别的。

  • 内存溢出(Out of Memory)
    当系统无法提供应用程序所需内存时,会导致应用程序抛出内存溢出的错误。
  • 内存泄露(Memory Leak)
    应用程序中一些被分配的内存,在使用完之后,没有及时被垃圾回收器进行回收(释放),导致一部分无效的内存被占用着。

当内存泄露积累到一定程度,就会发生内存溢出。而内存溢出导致的结果是应用程序被杀死。

场景


  1. 内存溢出

const obj = {}
for (let i = 0; i < 10000; i++) {
  obj[i] = new Array(1000000)
}
// 将会崩溃


  1. 内存泄露
  • 意外的全局变量
  • 闭包
  • setInterval 没有及时清除
  • DOM 引用未移除
  • ...


未完待续...

目录
相关文章
|
2月前
|
存储 缓存 JavaScript
请描述一种JavaScript内存泄漏的情况,并说明如何避免这种情况的发生。
JavaScript内存泄漏常由闭包引起,导致无用对象滞留内存,影响性能。例如,当一个函数返回访问大型对象的闭包,即使函数执行完,对象仍被闭包引用,无法被垃圾回收。防止泄漏需及时解除引用,注意事件监听器清理,使用WeakMap或WeakSet,定期清理缓存,以及利用性能分析工具检测。
13 2
|
3月前
|
弹性计算 运维 搜索推荐
幻兽帕鲁内存溢出怎么办,一键设置定时重启,修改虚拟内存,定时清理,轻松解决卡顿!再也不怕爆内存了!
幻兽帕鲁的内存溢出问题,玩久了确实会变卡。这里给出三个解决思路:第一种方法是定时进行内存清理(装个软件就可以),网上也有很多教程,我会把下载地址放在文章后面,大家可以去下载。第二种方法是调大虚拟内存,这个可以一键设置。第三种方法是定时重启游戏服务,这个也可以一键设置。这三种方法我下面都会教给大家,可以有效解决内存增长过快的问题,避免游戏卡顿甚至崩溃。
479 3
|
2天前
|
存储 缓存 JavaScript
【Web 前端】JS哪些操作会造成内存泄露?
【4月更文挑战第22天】【Web 前端】JS哪些操作会造成内存泄露?
|
15天前
|
JavaScript 前端开发
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 内存溢出问题
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 内存溢出问题
17 1
|
1月前
|
JavaScript 前端开发 Java
JavaScript中的内存泄露:如何避免及修复
JavaScript中的内存泄露:如何避免及修复
28 3
|
3月前
|
SQL Java Apache
Flink内存问题之内存溢出如何解决
Apache Flink是由Apache软件基金会开发的开源流处理框架,其核心是用Java和Scala编写的分布式流数据流引擎。本合集提供有关Apache Flink相关技术、使用技巧和最佳实践的资源。
|
4月前
|
前端开发 JavaScript 算法
JavaScript 内存管理的秘密武器:垃圾回收(下)
JavaScript 内存管理的秘密武器:垃圾回收(下)
JavaScript 内存管理的秘密武器:垃圾回收(下)
|
4月前
|
前端开发 JavaScript 算法
JavaScript 内存管理的秘密武器:垃圾回收(上)
JavaScript 内存管理的秘密武器:垃圾回收(上)
JavaScript 内存管理的秘密武器:垃圾回收(上)
|
4月前
|
Web App开发 前端开发 JavaScript
JavaScript 内存泄漏的检测与防范:让你的程序更稳定
JavaScript 内存泄漏的检测与防范:让你的程序更稳定
JavaScript 内存泄漏的检测与防范:让你的程序更稳定
|
4月前
|
缓存 JavaScript 前端开发
从引擎到垃圾回收器:JavaScript内存管理全方位解析(二)
从引擎到垃圾回收器:JavaScript内存管理全方位解析