图说前端 - 内存管理(1/3)
本系列共三篇
要理解为什么将 ArrayBuffer 和 SharedArrayBuffer 添加到 JavaScript 中,您需要了解一些内存管理。
内存
你可以把机器中的内存想象成一堆盒子。我认为这些就像你在办公室里的邮箱,或者学龄前儿童储存他们东西的小房间。
如果你需要给其他孩子留些东西,你可以把它放在盒子里。
在这些盒子的旁边,有一些数字,这就是内存地址。是你告诉别人在哪里可以找到你留给他们东西的方式。
这些盒子中的每一个都是相同的尺寸,可以容纳一定数量的信息。盒子的大小取决于机器。这个大小被称为字长。通常是 32 位或 64 位。但是为了更容易显示,我将使用 8 位的字长大小。
如果我们想把数字 2 放在其中一个盒子里,我们可以很容易地做到,因为数字是 易于用二进制表示 。
如果我们想要的不是数字呢?比如字母H?
我们需要有一种方法将它表示为一个数字。要做到这一点,我们需要一个编码,比如 UTF-8 。我们需要一些东西来把它变成那个数字…… 比如编码器环。然后我们可以储存它。
当我们想把它从盒子里拿回来时,我们必须把它通过解码器翻译回H。
自动内存管理
当使用JavaScript时,你实际上不需要考虑内存。它是从你身边抽象出来的。这意味着你不会直接接触内存。
相反,JS引擎充当中介。它为你管理内存。
让我们看一些 JS 代码,比如 React,想要创建一个变量。
JS 引擎所做的是通过编码器运行该值,以获得该值的二进制表示。
它会在内存中找到可以放入二进制表示的空间。此过程称为分配内存。
然后,引擎将跟踪这个变量是否仍然被程序的代码引用,如果变量不能被引用,内存将被回收,以便 JS 引擎可以在那里放置新的值。
这个观察变量的过程 -- 字符串、对象和其他类型的值进入内存 -- 并在无法再访问它们时清除它们的过程被称为垃圾回收。
像 JavaScript 这样的语言,代码不直接处理内存,被称为自动内存管理语言。
这种自动内存管理可以使开发人员更轻松。但这也增加了一些开销。这种开销有时会使性能不可预测。
手动内存管理
具有手动管理内存的语言是不同的。例如,让我们看看如果用 C 编写,React 将如何与内存一起工作 (现在可以通过 WebAssembly 实现 )。
C 没有 JavaScript 在内存上执行的抽象层,因此你需要直接在内存上操作。您可以从内存中加载东西,也可以将东西存储到内存中。
当您将 C 或其他语言编译到 WebAssembly 时,您使用的工具将在 WebAssembly 中添加一些帮助程序代码。例如,它将添加执行编码和解码字节的代码,此代码称为运行时环境。运行时环境将帮助 JS 引擎处理 一些为 JS 做的事情。
但是对于手动管理的语言,该运行时不包括垃圾回收。
这并不意味着你完全是一个人。即使在具有手动内存管理的语言中,您通常也会从语言运行时获得一些帮助。例如,在 C 中,运行时将跟踪哪些内存地址在所谓的空闲列表中打开。
您可以使用该函数 malloc
( memory allocate 内存分配的缩写) 要求运行时找到一些适合您的数据的内存地址。这将从空闲列表中删除这些地址。当你处理完这些数据后,你必须告诉 free
释放内存。然后这些地址将被添加回空闲列表。
你必须弄清楚什么时候调用这些函数。这就是为什么它被称为手动内存管理 -- 你自己管理内存。
作为一名开发人员,很难弄清楚何时清除内存的不同部分。如果你在错误的时间做,它会导致错误,甚至导致安全漏洞,但是如果你不这样做,你的内存就会耗尽。
这就是为什么许多现代语言使用自动内存管理-以避免人为错误,但这是以牺牲性能为代价的,我会解释更多关于此 下一篇文章 。
评论