内存管理速成课程

这是 3 部分系列中的第一篇文章

  1. 内存管理速成课程
  2. ArrayBuffers 和 SharedArrayBuffers 漫画入门
  3. 使用 Atomics 避免 SharedArrayBuffers 中的竞态条件

为了理解为什么 ArrayBuffer 和 SharedArrayBuffer 被添加到 JavaScript 中,你需要了解一些关于内存管理的知识。

你可以把机器中的内存想象成一组箱子。我把它想象成办公室里那些邮箱,或者幼儿园孩子们用来存放东西的储物柜。

如果你需要给其他孩子留东西,你就可以把它放在一个箱子里。

A column of boxes with a child putting something in one of the boxes

在每个箱子旁边,你都有一个数字,那就是内存地址。这就是你告诉别人在哪里找到你为他们留下的东西的方式。

每个箱子都一样大小,可以容纳一定的信息量。箱子的尺寸取决于机器。这个尺寸被称为字长。它通常是 32 位或 64 位。但为了便于展示,我将使用 8 位的字长。

A box with 8 smaller boxes in it

如果我们想把数字 2 放入这些箱子中的一个,我们可以很容易地做到。数字很容易用二进制表示。

The number two, converted to binary 00000010 and put inside the boxes

但是,如果我们想要的是非数字的东西呢?比如字母 H?

我们需要一种方法将其表示为数字。为此,我们需要一种编码,比如 UTF-8。我们还需要一些东西将其转换为这个数字……比如一个编码环。然后我们就可以存储它了。

The letter H, put through an encoder ring to get 72, which is then converted to binary and put in the boxes

当我们想要把它从箱子里取出来时,我们需要把它通过解码器,将其翻译回 H。

自动内存管理

当你在 JavaScript 中工作时,你实际上不需要考虑内存。它对你来说是抽象的。这意味着你不会直接接触内存。

相反,JS 引擎充当中间人。它会为你管理内存。

A column of boxes with a rope in front of it and the JS engine standing at that rope like a bouncer

所以,假设一些 JS 代码,比如 React,想要创建一个变量。

Same as above, with React asking the JS engine to create a variable

JS 引擎所做的是将该值通过编码器,获得该值的二进制表示。

The JS engine using an encoder ring to convert the string to binary

它会在内存中找到可以容纳这个二进制表示的空间。这个过程被称为分配内存。

The JS engine finding space for the binary in the column of boxes

然后,引擎会跟踪这个变量是否仍然可以在程序中的任何地方访问。如果这个变量不再可以访问,内存将被回收,以便 JS 引擎可以将新的值放入其中。

The garbage collector clearing out the memory

这个观察变量(字符串、对象和其他存储在内存中的值)并在它们不再可以访问时清除它们的过程称为垃圾收集。

像 JavaScript 这样的语言,代码不直接处理内存,被称为内存管理语言。

这种自动内存管理可以使开发人员的生活更轻松。但它也增加了一些开销。而这些开销有时会使性能变得不可预测。

手动内存管理

手动管理内存的语言则不同。例如,让我们看看如果 React 是用 C 语言编写的,它将如何与内存交互(现在这已经可以实现了,使用WebAssembly)。

C 没有像 JavaScript 那样在内存上进行抽象。相反,你直接操作内存。你可以从内存中加载东西,也可以将东西存储到内存中。

A WebAssembly version of React working with memory directly

当你将 C 或其他语言编译成 WebAssembly 时,你使用的工具会将一些辅助代码添加到你的 WebAssembly 中。例如,它会添加执行字节编码和解码的代码。这段代码被称为运行时环境。运行时环境将帮助处理 JS 引擎为 JS 做的一些事情。

An encoder ring being shipped down as part of the .wasm file

但是对于手动管理的语言,运行时环境将不包括垃圾收集。

这并不意味着你完全依靠自己。即使在手动管理内存的语言中,你通常也会得到来自语言运行时环境的帮助。例如,在 C 中,运行时环境会跟踪哪些内存地址是开放的,在一个叫做空闲列表的东西中。

A free list next to the column of boxes, listing which boxes are free right now

你可以使用函数 malloc(memory allocate 的缩写)来请求运行时环境找到一些可以容纳你的数据的内存地址。这将从空闲列表中取出这些地址。当你完成了对这些数据的操作后,你需要调用 free 来释放内存。然后这些地址将被添加回空闲列表。

你需要自己弄清楚何时调用这些函数。这就是它被称为手动内存管理的原因——你自行管理内存。

作为一名开发者,弄清楚何时清除内存的不同部分可能很困难。如果你在错误的时间这样做,可能会导致错误,甚至会导致安全漏洞。如果你没有这样做,你就会耗尽内存。

这就是为什么许多现代语言使用自动内存管理的原因——为了避免人为错误。但这是以性能为代价的。我会在下一篇文章中对此进行更详细的解释。

关于 Lin Clark

Lin 在 Mozilla 的高级开发部门工作,专注于 Rust 和 WebAssembly。

更多由 Lin Clark 撰写的文章…


19 条评论

  1. jero

    很棒的贡献,让我明白了。

    我可以将其翻译成拉丁美洲西班牙语吗?

    2017年6月15日 12:53

    1. Lin Clark

      是的,我很乐意看到西班牙语的翻译!请确保链接回原文,并在完成翻译后将链接添加到此处。谢谢!

      2017年6月18日 07:16

    2. oxicode

      +1

      2017年6月27日 08:30

  2. Nicolás Isnardi

    解释这个概念的方式很棒!感谢你的辛勤工作!

    2017年6月16日 04:44

  3. jobou

    我喜欢你的图片!:)

    2017年6月16日 12:45

  4. Shayan

    非常有帮助的文章

    2017年6月17日 10:50

  5. Andrew

    很棒的文章。干得好。

    2017年6月17日 15:30

  6. p thompson

    很棒的解释——有帮助的图形!:)

    2017年6月17日 22:07

  7. Darshan k.

    对于像我这样的新手来说,绝对有帮助。
    简短而甜美。我喜欢你解释这个概念的方法。继续努力!

    干杯!
    /Darshan

    2017年6月18日 17:26

  8. Segey

    一篇很棒的文章。非常清晰、简单、说明性强,对了解内存系统的工作原理很有帮助。这就是学生应该在大学里学习的方式。我已经转发给了我的女儿!:)

    2017年6月18日 21:42

  9. Andrey Melikhov

    嗨,又见面了!
    我已经发布了俄语翻译版本https://medium.com/devschacht/a-crash-course-in-memory-management-b4863e000a5f!:)

    2017年6月19日 00:38

  10. Joey Zhou

    很棒的作品,我可以将其翻译成中文版吗?

    2017年6月19日 19:38

    1. Lin Clark

      是的,我很乐意看到中文版!:) 请确保链接回原文,并在发布后将链接贴回此处。谢谢!

      2017年6月20日 05:19

      1. Joey Zhou

        中文版本已发布,希望你喜欢。
        http://diule.site/2017/06/23/memory-management/

        2017年6月23日 07:17

  11. Zhao Zhiming

    我刚刚将这系列文章翻译成了中文。

    http://zhaozhiming.github.io/blog/2017/06/20/a-crash-course-in-memory-management-zh/

    2017年6月22日 05:44

  12. Tayyab

    很棒的工作,阅读你的作品很有趣

    2017年6月24日 21:11

  13. Charles

    很棒的文章……谢谢

    2017年6月25日 14:41

  14. Prakash

    棒极了。即使是非技术人员也能理解。向你致敬。

    2017年6月28日 20:14

  15. 0xnntt

    你无法想象这篇文章对我来说有多有趣!
    你在文章中使用的图像语言非常独特,也很有趣。
    感谢你的精彩文章和精彩的演示。

    2017年6月30日 14:05

这篇文章的评论已关闭。