翻译自A crash course in memory management。
This is the 1st article in a 3-part series:
这是由 3 部分组成的系列文章中的第 1 篇文章:
- A crash course in memory management**内存管理速成课
- A cartoon intro to ArrayBuffers and SharedArrayBuffers **卡通介绍ArrayBuffers 和 SharedArrayBuffers
- Avoiding race conditions in SharedArrayBuffers with Atomics **在 Sharedarraybuffers 中使用 Atomics 来避免竞态条件
To understand why ArrayBuffer and SharedArrayBuffer were added to JavaScript, you need to understand a bit about memory management.
为了理解为什么JavaScript中会有ArrayBuffer和SharedArrayBuffer,你需要理解一点内存管理。
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?
如果我们想要一些不是数字的东西怎么办?喜欢字母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.
我们需要有一种方法将其表示为数字。要做到这一点,我们需要一个编码,类似于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。
Automatic memory management 自动内存管理
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.
当你工作中使用JavaScript时,你实际上不需要考虑管理这个内存。内存被抽象出来了,这意味着您不会直接接触内存。
Instead, the JS engine acts as an intermediary. It manages the memory for you.
相反,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引擎将跟踪此变量是否仍可从程序中的任何位置访问。如果无法再访问该变量,则将回收内存,以便 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.
像JavaScript这样代码不直接处理内存的语言,被称为内存管理语言。
This automatic memory management can make things easier for developers. But it also adds some overhead. And that overhead can sometimes make performance unpredictable.
这种自动内存管理可以使开发人员更轻松地完成工作。但它也增加了一些开销。这种开销有时会使性能不可预测。
Manual memory management 手动管理内存
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将如何与内存一起工作。
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时,你使用的工具会将一些helper程序代码添加到WebAssembly中。例如,添加的helper运行时环境(runtime environment)可以理解为有执行编码和解码字节功能的代码。运行时环境将帮助处理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.
你可以使用函数"malloc"(内存分配的缩写)来要求运行时找到一些适合你数据的内存地址。这会将这些地址从空闲列表中删除。处理完这些数据后,必须调用"free"来解除分配的内存。然后,这些地址将被添加回空闲列表。
You have to figure out when to call those functions. That’s why it’s called manual memory management—you manage the memory yourself.
你必须弄清楚何时调用这些函数。这就是为什么它被称为手动内存管理 - 开发人员自己管理内存。
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.
这就是为什么许多现代语言使用自动内存管理来避免人为错误的原因。但这是以性能为代价的。我将在下一篇文章中对此进行更多解释。