[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]