前言
2020年最后一天,又走过了一年了。今日前端早读课文章由@laampui翻译授权分享。
正文从这开始~~
内存泄漏是每一位开发者最终都会遇到的问题。它存在于大多数的编程语言里,即使是能够自动管理内存的语言也不例外。内存泄漏会导致一些如应用缓慢、崩溃、高延迟等问题。
在这篇文章中,我们会了解到什么是内存泄漏以及如何在 Node.js 中避免它。虽然这篇文章着重点在 NodeJS,但应该也适用于 JavaScript 和 TypeScript。规避内存泄漏有助于你的应用更高效地利用资源同时也能带来性能提升。
JavaScript 中的内存管理
要理解内存泄漏,我们首先需要理解 NodeJS 是如何管理内存的。这意味着需要了解内存是如何被 NodeJS 的 JavaScript 引擎管理的。对于 JavaScript,NodeJS 使用 V8 引擎,对于内存是如何被 V8 组织及利用,你可以参阅 Visualizing memory management in V8 Engine 来获得更好的理解。
总结上面提及的那篇参阅文章:
内存主要分为栈和堆。
栈:存放静态数据,包括方法(函数)帧、原始值和指向对象的指针。这里的空间是被操作系统管理的。
堆:V8 存放对象或动态数据。这是内存区域中最大的一块并且这里是 垃圾回收(GC) 生效的地方。
V8 通过垃圾收集管理堆内存。简单地说,它会释放没有被引用的对象。例如,没有被栈直接或间接引用(通过另一个对象引用)的对象,它的内存空间都会被释放以用于新对象的创建。都会被释放内存空间用于新对象的创建。
V8 的垃圾收集器主要负责回收处理无用的内存,并提供给 V8 进程重复使用。V8 垃圾收集器是区分新老生代的(堆中的对象按它们的存放时间分组并会在不同的阶段被清理)。V8 的垃圾回收有两个阶段和三种算法。
什么是内存泄漏
简单来说,内存泄漏就是堆上的一块孤立内存,这小块内存不再被程序使用并且也没有被垃圾收集器释放回操作系统,所以,这是一块没有被使用的内存。这样的内存块持续增加可能会导致应用没有足够内存空间去支撑其继续工作,也可能会导致你的操作系统没有足够的内存可供分配,进而导致系统缓慢或崩溃。
什么导致了内存泄漏
自动内存管理(如 V8 中的垃圾收集机制)目的在于避免内存泄漏,像循环引用不再是一个需要开发者关注的问题,然而内存泄漏依然可能发生,也许是因为预料之外的堆中的引用亦或是各种原因。一些常见的原因列举如下。
全局变量:因为 JavaScript 中的全局变量被根节点(window 或 global this)引用,所以它们在整个应用生命周期中不会被收集,即会一直占用内存。这同样也适用于那些被全局变量(或其子属性)引用的对象,通过根节点引用数量庞大的对象可能导致内存泄漏。
多个引用: 当同一个对象被多个对象引用时,当其中一个引用被挂起,可能会导致内存泄漏。
闭包: JavaScript 闭包有一个很酷的特性,就是能够保存被它关联的上下文,当一个闭包持有一个引用,