林志玲 发表于 2024-8-16 16:01:40

[JS] 内存管理与V8垃圾回收机制

内存管理简介

内存管理是控制和协调软件应用程序访问计算机内存的方式的过程。
当一个程序运行在某个操作系统上时,进程需要拥有对RAM的访问权限,以实现:

[*]载入程序需要执行的字节码;
[*]存储正在执行的程序所使用的数据值和数据结构;
[*]载入程序执行所需的任何运行时系统。
一个进程在启动时,会向操作系统申请内存空间。一个进程的内存空间被分为多个区域,其中最主要的两个区分别是栈区和堆区。
栈区

栈区的内存分配符合栈先进后出这一特性,并且栈区的大小通常是固定的。

[*]与堆区不同,栈区的变量查询比较简单,且通常只在栈顶进行数据的存储和读取,只需要维护一个栈指针即可,读写操作非常快;
[*]存储在栈中的数据必须在编译时确定其大小,并且在运行时不会动态变化;
[*]在进程中每调用一个函数,就会推入一个栈帧(stack frame)。每一个栈帧都记录着函数执行所需要的数据。例如,当一个函数声明了一个新变量时,变量会被添加到栈顶的栈帧中,当函数执行完毕返回时,栈帧会被清除,内部所有变量也都会被清除;
[*]多线程进程的每一个线程拥有各自的调用栈;
[*]栈区的内存管理由操作系统负责;
[*]常见的存储于栈区的数据有:局部变量、指针、函数帧;
[*]栈区常见的异常是“栈溢出异常”(stack overflow error),这是因为栈区相比于堆区要小很多。
堆区

堆区用于动态地分配内存,程序需要通过指针在堆区中查找数据。

[*]堆区与栈区相比可以存储更多数据,但是查询数据比较慢;
[*]堆区用于存储动态大小的数据;
[*]多线程进程的多个线程共享一个堆区;
[*]常见的存储于堆区的数据有:全局变量,对象、字符串等引用类型;
为什么需要关注内存管理
内存的容量有限,如果程序不加节制地使用内存而不释放,最终会导致内存耗尽,可能导致程序或操作系统崩溃。因此,编程语言通常提供自动内存管理的机制,以避免这种情况发生。
在讨论内存管理时,我们通常指的是如何管理堆内存。

[*]这是因为栈内存的管理由操作系统自动完成,通常只要避免递归调用导致栈溢出,就不会出错;
[*]而堆内存需要程序员手动管理分配与释放,虽然自由度更好,但也带来了更大的风险与复杂度。
内存管理方法


[*]手动内存管理
开发者需要自行分配和释放对象的内存。例如,C 和 C++ 提供了 malloc、realloc、calloc 和 free 函数来管理内存,开发者必须在程序中分配和释放堆内存,并有效地使用指针来管理内存。
[*]垃圾回收(GC)
垃圾回收是现代语言中最常见的内存管理方式之一,通常在某些时间间隔运行,因此可能会产生称为“暂停时间”的轻微开销。JVM(Java/Scala/Groovy/Kotlin)、JavaScript、C#、Golang、OCaml 和 Ruby 默认使用垃圾回收进行内存管理。

[*]标记 - 清除算法
这通常是一个两阶段的算法,首先标记仍然被引用的对象为“存活”,然后在下一阶段释放未存活对象的内存。
[*]引用计数算法
每个对象都会有一个引用计数,当对它的引用发生变化时,该计数会增加或减少,当计数变为零时,就会进行垃圾回收。由于无法处理循环引用,这种方法很少被使用。

V8 引擎中的内存管理

V8 引擎被 NodeJS、Deno、Electron 等运行时以及 Chrome、Chromium、Brave、Opera 和 Microsoft Edge 等浏览器使用。
由于 JavaScript 是一种解释性语言,它需要一个引擎来解释和执行代码。V8 引擎负责解释 JavaScript 并将其编译为原生机器码。
V8 是用 C++ 编写的,可以嵌入到任何 C++ 应用程序中。
V8内存结构

JavaScript 是单线程的,V8 引擎为每个 JavaScript 上下文生成一个进程;如果使用了工作线程(service workers),则 V8 引擎会为每个工作线程生成一个新的进程。

<blockquote>
图片来源:<a href="https://deepu.tech/memory-management-in-v8/" target="_blank" rel="noopener nofollow">
来源:https://www.cnblogs.com/feixianxing/p/18362078/memory-management-and-garbage-collection-in-v8
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: [JS] 内存管理与V8垃圾回收机制