原文:A crash course in memory management
本文译自Lin Clark 内存管理的卡通介绍系列,渣翻译,因此附上英文原文。
概述
To understand why ArrayBuffer and SharedArrayBuffer were added to JavaScript, you need to understand a bit about memory management.
想要了解为什么将 ArrayBuffer
和 SharedArrayBuffer
添加到 JavaScript
中,你需要了解一些内存管理。
You can think of memory in a machine as a bunch of boxes. I think of these like the mailboxes that you have in offices, or the cubbies that pre-schoolers have to store their things.
If you need to leave something for one of the other kids, you can put it inside a box.
你可以将计算机的内存看做一堆盒子。就像你办公室的邮箱,或者是学龄前儿童的储物柜。
如果你想为其他孩子留下一些东西,你可以把它放在一个盒子里。
Next to each one of these boxes, you have a number, which is the memory address. That’s how you tell someone where to find the thing you’ve left for them.
Each one of these boxes is the same size and can hold a certain amount of info. The size of the box is specific to the machine. That size is called word size. It’s usually something like 32-bits or 64-bits. But to make it easier to show, I’m going to use a word size of 8 bits.
在每个盒子的旁边都有一个数字,他就是内存地址,它用来告诉别人你放东西的位置。
这些盒子都有相同的尺寸,可以容纳一定量的信息。每个盒子的尺寸取决于物理机器,这个尺寸叫做字长。它通常是 32
位或 64
位,但是为了更容易演示,我们使用8位的字长。
If we wanted to put the number 2 in one of these boxes, we could do it easily. Numbers are easy to represent in binary.
如果我们想把数字2放进其中一个盒子,这很容易做到,数字很容易用二进制表示。
What if we want something that’s not a number though? Like the letter H?
We’d need to have a way to represent it as a number. To do that, we need an encoding, something like UTF-8. And we’d need something to turn it into that number… like an encoder ring. And then we can store it.
如果我们想要的东西不是数字呢,比如字母 H
?
我们需要用一种方式把它表示为数字,为了做到这一步,我们需要对它编码,比如 UTF-8
。我们需要一些东西把它转变成数字,比如编码器环,然后就可以存储它。
When we want to get it back out of the box, we’d have to put it through a decoder to translate it back to H.
当我们想要获得它的时候,把数字从盒子中取出来,放进解码器进行翻译,又变成了字母 H
。
自动内存管理
When you’re working in JavaScript you don’t actually need to think about this memory. It’s abstracted away from you. This means you don’t touch the memory directly.
Instead, the JS engine acts as an intermediary. It manages the memory for you.
当你使用 JavaScript
时,实际上并不需要考虑内存。它是一个离你很远的抽象的概念,这意味着你不必直接操作内存。
相反的,JS
引擎充当中介,它替你管理内存。
So let’s say some JS code, like React, wants to create a variable.
让我们看一些 JS
代码,比如 React
,想要创建一个变量。
What the JS engine does is run that value through an encoder to get the binary representation of the value.
JS 引擎做事是运行编码器获得值的二进制表示。
And it will find space in the memory that it can put that binary representation into. This process is called allocating memory.
并且它在内存中找到可以存放这个二进制表示的值的空间,这个过程称为分配内存。
Then, the engine will keep track of whether or not this variable is still accessible from anywhere in the program. If the variable can no longer be reached, the memory is going to be reclaimed so that the JS engine can put new values there.
然后,引擎将跟踪该变量是否仍然可以从程序的任何地方访问。如果变量不能被访问,存放的内存将被回收,以便 JS
引擎可以存放新值。
This process of watching the variables—strings, objects, and other kinds of values that go in memory—and clearing them out when they can’t be reached anymore is called garbage collection.
这个观察变量(字符串,对象和内存中其他类型的值),并且当它们不能被访问的时候清除的过程被称为垃圾收集。
Languages like JavaScript, where the code doesn’t deal with memory directly, are called memory-managed languages.
This automatic memory management can make things easier for developers. But it also adds some overhead. And that overhead can sometimes make performance unpredictable.
像 JavaScript
这类的代码不在代码中直接处理内存的语言,被称为内存管理语言。这种自动的内存管理可以使开发人员更轻松。但它增加了一些开销,而这种开销有时会使性能变得不可预测。
手动内存管理
Languages with manually managed memory are different. For example, let’s look at how React would work with memory if it were written in C (which would be possible now with WebAssembly).
手动管理内存的语言则不同。比如,我们来看看如果使用 C
语言来写, React
怎样操作内存(现在可以通过 WebAssembly
来实现)。
C doesn’t have that layer of abstraction that JavaScript does on the memory. Instead, you’re operating directly on memory. You can load things from memory, and you can store things to memory.
C 语言没有类似于 JavaScript 的在内存上的抽象层,而是直接在内存上操作。你可以从直接内存中加载内容,也可以直接将内容存储到内存中。
When you’re compiling C or other languages down to WebAssembly, the tool that you use will add in some helper code to your WebAssembly. For example, it would add code that does the encoding and decoding bytes. This code is called a runtime environment. The runtime environment will help handle some of the stuff that the JS engine does for JS.
当你将 C 语言或其他语言编译到 WebAssembly
时,你使用的工具将在 WebAssembly
中添加一些帮助代码。例如,添加编码和解码二进制字节的代码,这个代码被成为运行时环境,运行时环境将帮助处理一些之前 JS
引擎为 JS
做的事情。
But for a manually managed language, that runtime won’t include garbage collection.
This doesn’t mean that you’re totally on your own. Even in languages with manual memory management, you’ll usually get some help from the language runtime. For example, in C, the runtime will keep track of which memory addresses are open in something called a free list.
但是对于一个手动管理内存的语言而言,该运行时环境将不包括垃圾回收。
这不意味着你需要自己做全部的事情,即使是手动内存管理的语言,也通常会在语言运行期获得帮助。比如,在 C
语言中,运行期会追踪哪些地址是可用的,并放在空闲列表中。
You can use the function malloc (short for memory allocate) to ask the runtime to find some memory addresses that can fit your data. This will take those addresses off of the free list. When you’re done with that data, you have to call free to deallocate the memory. Then those addresses will be added back to the free list.
You have to figure out when to call those functions. That’s why it’s called manual memory management—you manage the memory yourself.
你可以使用 malloc
(内存分配的简写)函数来要求在运行时找到一些可以存储你的数据的内存地址。这将把这些地址从空闲列表中删除。当你使用完这些数据后,您必须使用 free
函数释放内存。那么这些地址将重新被添加到空闲列表。
你必须弄清楚什么时候调用这些功能,这就是为什么它被称为手动内存管理:你需要自己管理内存。
As a developer, figuring out when to clear out different parts of memory can be hard. If you do it at the wrong time, it can cause bugs and even lead to security holes. If you don’t do it, you run out of memory.
This is why many modern languages use automatic memory management—to avoid human error. But that comes at the cost of performance. I’ll explain more about this in the next article.
作为开发者,搞清楚什么时候清除不同部分的内存可能很难。如果在错误的时间进行操作,可能会导致错误,甚至导致安全漏洞,但是如果你不清除内存,你的内存就会耗尽。
这就是为什么许多现代语言使用自动内存管理的原因:为了避免人为的错误。但这是以牺牲性能为代价的,我将在下一篇文章中更详细地解释这一点。