From ac207a438136719f126ba15a6d3c9186e43b91cf Mon Sep 17 00:00:00 2001 From: familyboat <2015301110129@whu.edu.cn> Date: Sat, 19 Oct 2024 20:50:09 +0800 Subject: [PATCH 01/27] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/javascript/memory_management/index.md | 259 +++++++++++++----- 1 file changed, 186 insertions(+), 73 deletions(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 818848c2f5f938..18c45bad2b42ca 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -1,13 +1,13 @@ --- title: 内存管理 slug: Web/JavaScript/Memory_management +l10n: + sourceCommit: e03b13c7e157ec7b7bb02a6c7c4854b862195905 --- {{JsSidebar("Advanced")}} -## 简介 - -像 C 语言这样的底层语言一般都有底层的内存管理接口,比如 `malloc()`和`free()`。相反,JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。这个“自动”是混乱的根源,并让 JavaScript(和其他高级语言)开发者错误的感觉他们可以不关心内存管理。 +底层语言(如 c 语言)拥有手动的内存管理基本操作,例如:[`malloc()`](https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) 和 [`free()`](https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Overview_of_functions)。相反,JavaScript 是在创建对象时自动分配内存,并在不再使用时自动释放内存(*垃圾回收*)。这个自动性是混乱的潜在根源:它让开发者错误地以为他们不需要担心内存管理。 ## 内存生命周期 @@ -17,31 +17,31 @@ slug: Web/JavaScript/Memory_management 2. 使用分配到的内存(读、写) 3. 不需要时将其释放\归还 -所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像 JavaScript 这些高级语言中,大部分都是隐含的。 +在所有语言中,第二点都是显式的。在底层语言中,第一点和第三点是显式的,但在高级语言中(如 JavaScript),大多数是隐式的。 ### JavaScript 的内存分配 #### 值的初始化 -为了不让程序员费心分配内存,JavaScript 在定义变量时就完成了内存分配。 +为了不让程序员费心内存分配,JavaScript 在值初次声明时自动分配内存。 ```js -var n = 123; // 给数值变量分配内存 -var s = "azerty"; // 给字符串分配内存 +const n = 123; // 为数字分配内存 +const s = "azerty"; // 为字符串分配内存 -var o = { +const o = { a: 1, b: null, -}; // 给对象及其包含的值分配内存 +}; // 为对象及其包含的值分配内存 -// 给数组及其包含的值分配内存(就像对象一样) -var a = [1, null, "abra"]; +// 为数组及其包含的值分配内存(就像对象一样) +const a = [1, null, "abra"]; function f(a) { return a + 2; -} // 给函数(可调用的对象)分配内存 +} // 为函数(可调用的对象)分配内存 -// 函数表达式也能分配一个对象 +// 函数表达式也会分配内存 someElement.addEventListener( "click", function () { @@ -53,88 +53,97 @@ someElement.addEventListener( #### 通过函数调用分配内存 -有些函数调用结果是分配对象内存: +有些函数调用的结果是为对象分配内存: ```js -var d = new Date(); // 分配一个 Date 对象 +const d = new Date(); // 为 Date 对象分配内存 -var e = document.createElement("div"); // 分配一个 DOM 元素 +const e = document.createElement("div"); // 为 DOM 元素分配内存 ``` -有些方法分配新变量或者新对象: +有些方法为新值或新对象分配内存: ```js -var s = "azerty"; -var s2 = s.substr(0, 3); // s2 是一个新的字符串 -// 因为字符串是不变量, +const s = "azerty"; +const s2 = s.substr(0, 3); // s2 是一个新的字符串 +// 因为字符串是不可变的值, // JavaScript 可能决定不分配内存, // 只是存储了 [0-3] 的范围。 -var a = ["ouais ouais", "nan nan"]; -var a2 = ["generation", "nan nan"]; -var a3 = a.concat(a2); -// 新数组有四个元素,是 a 连接 a2 的结果 +const a = ["ouais ouais", "nan nan"]; +const a2 = ["generation", "nan nan"]; +const a3 = a.concat(a2); +// 有四个元素的新数组,由 a 和 a2 元素连接而成。 ``` ### 使用值 -使用值的过程实际上是对分配内存进行读取与写入的操作。读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。 +使用值基本上是指在分配的内存上进行读写。读写变量值或对象的属性值、甚至给函数传递参数都会使用值。 ### 当内存不再需要使用时释放 -大多数内存管理的问题都在这个阶段。在这里最艰难的任务是找到“哪些被分配的内存确实已经不再需要了”。它往往要求开发人员来确定在程序中哪一块内存不再需要并且释放它。 +大多数内存管理的问题出现在这个阶段。这个阶段最难的任务是确定已分配的内存何时不再需要了。 + +底层语言要求开发人员手动确定在程序的哪个点不再需要已分配的内存并释放这块内存。 -高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是[无法判定的](http://en.wikipedia.org/wiki/Decidability_%28logic%29)(无法通过某种算法解决)。 +一些高级语言(如 JavaScript)使用的是自动内存管理(也就是[垃圾回收]()(GC))的形式。垃圾回收器的目的是监控内存分配和确定一块已分配的内存何时不再需要并释放这块内存。这个自动过程是个近似的说法,因为确定一块特定的内存是否仍然需要这个一般性问题是[无法判定的](http://en.wikipedia.org/wiki/Decidability_%28logic%29)。 ## 垃圾回收 -如上文所述自动寻找是否一些内存“不再需要”的问题是无法判定的。因此,垃圾回收实现只能有限制的解决一般问题。本节将解释必要的概念,了解主要的垃圾回收算法和它们的局限性。 +如上文所述,自动寻找一些内存是否“不再需要”这个一般性问题是无法判定的。因此,垃圾回收器对这个一般性问题实现了一个存在限制的解决方案。本节将解释理解主要的垃圾回收算法及其相应的局限所必须的概念。 ### 引用 -垃圾回收算法主要依赖于引用的概念。在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显式),叫做一个对象引用另一个对象。例如,一个 Javascript 对象具有对它[原型](/zh-CN/JavaScript/Guide/Inheritance_and_the_prototype_chain)的引用(隐式引用)和对它属性的引用(显式引用)。 +垃圾回收算法依赖的主要概念是引用。在内存管理的上下文中,如果一个对象有访问另一个对象的权限(隐式或者显式),称作前面的对象引用后面的对象。例如,一个 Javascript 对象具有对它的[原型](/zh-CN/JavaScript/Guide/Inheritance_and_the_prototype_chain)的引用(隐式引用)和对它属性的引用(显式引用)。 + +在这个上下文中,“对象”的概念不仅指常规的 JavaScript 对象,还包括函数作用域(或者全局词法作用域)。 -在这里,“对象”的概念不仅特指 JavaScript 对象,还包括函数作用域(或者全局词法作用域)。 +### 引用计数垃圾回收 -### 引用计数垃圾收集 +> [!NOTE] +> 现代的浏览器不再使用引用计数进行垃圾回收。 -这是最初级的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。 +这是最初级的垃圾回收算法。此算法把确定对象是否仍然需要这个问题简化为确定对象是否仍有其他引用它的对象。如果没有指向该对象的引用,那么该对象称作“垃圾”或者可回收的。 -#### 示例 +示例 ```js -var o = { +let x = { a: { b: 2, }, }; -// 两个对象被创建,一个作为另一个的属性被引用,另一个被分配给变量 o -// 很显然,没有一个可以被垃圾收集 +// 创建了两个对象。一个作为另一个的属性被引用。 +// 另一个被赋值给变量‘x’。 +// 很显然,没有可以被垃圾回收的对象。 -var o2 = o; // o2 变量是第二个对“这个对象”的引用 +let y = x; +// 变量‘y’是第二个拥有对象引用的变量。 -o = 1; // 现在,“这个对象”只有一个 o2 变量的引用了,“这个对象”的原始引用 o 已经没有 +x = 1; +// 现在,起初在‘x’中的对象有唯一的引用,就是变量‘y’。 -var oa = o2.a; // 引用“这个对象”的 a 属性 -// 现在,“这个对象”有两个引用了,一个是 o2,一个是 oa +let z = y.a; +// 引用对象的‘a’属性。 +// 现在,这个对象有两个引用,一个作为属性, +// 另一个作为变量‘z’。 -o2 = "yo"; // 虽然最初的对象现在已经是零引用了,可以被垃圾回收了 -// 但是它的属性 a 的对象还在被 oa 引用,所以还不能回收 +y = "mozilla"; +// 起初在‘x’中的对象现在是零引用了。它可以被垃圾回收了。 +// 但是,它的属性‘a’仍被变量‘z’引用,所以这个对象还不能回收。 -oa = null; // a 属性的那个对象现在也是零引用了 -// 它可以被垃圾回收了 +z = null; +// 起初在 x 中的对象的属性‘a’是零引用了。这个对象可以被垃圾回收了。 ``` -#### 限制:循环引用 - -该算法有个限制:无法处理循环引用的事例。在下面的例子中,两个对象被创建,并互相引用,形成了一个循环。它们被调用之后会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。 +循环引用是一个限制。在下面的例子中,创建了两个对象,一个对象的属性引用另一个对象,形成了一个循环。在函数调用结束之后,它们离开了函数作用域。在那个点,它们不再被需要了,为它们分配的内存应该被回收。然而,引用计数算法不会认为它们可以被回收,因为每个对象至少还有一个指向自己的引用,这样的结果就是它们两个都不会被标记为可以被垃圾回收。循环引用是内存泄露的常见原因。 ```js function f() { - var o = {}; - var o2 = {}; - o.a = o2; // o 引用 o2 - o2.a = o; // o2 引用 o + const x = {}; + const y = {}; + x.a = y; // x 引用 y + y.a = x; // y 应用 x return "azerty"; } @@ -142,41 +151,145 @@ function f() { f(); ``` -#### 实际例子 +### 标记清除算法 + +这个算法将“对象不再需要”这个定义简化为“对象不可达”。 + +这个算法假定有一组叫做*根*的对象。在 Javascript 中,根是全局对象。垃圾回收器将定期从这些根开始,找到从这些根能引用到的所有对象,然后找到从这些对象能引用到的所有对象,等等。从根开始,垃圾回收器将找到所有可以到达的对象并收集所有不能到达的对象。 + +这个算法是对上一个算法的改进。因为对于引用计数算法,有零引用的对象实际上是不可达的,但是有引用的对象却不一定,就像在循环引用中看到的那样。 + +当前,所有现代的引擎搭载的是标记清除垃圾回收器。过去几年中,在 JavaScript 垃圾回收领域做出的改进(分代/增量/并发/并行 垃圾回收)都是这个算法的实现改进,而不是垃圾回收算法本身的改进,也不是何时“对象不再需要”这个定义的简化。 + +这个方法的直接好处就是循环不再是一个问题。在上面的示例中,在函数调用返回之后,从全局对象可达的任何资源都将不再引用这两个对象。因此,垃圾回收器会认为它们不可达并回收为它们分配的内存。 + +然而,手动控制垃圾回收的能力仍不存在。有时候动手决定何时释放内存以及释放哪块内存会很方便。为了释放对象的内存,需要显式地变成不可达。在 JavaScript 中,编程式地触发垃圾回收也不可能——永不可能出现在核心语言中,尽管引擎可能在可选的标志中暴露了相关的 API。 + +## 配置引擎的内存模型 + +JavaScript 引擎典型地提供了暴露内存模型地标志。例如,Node.js 为配置和除错内存问题提供了暴露底层的 V8 机制的额外选项和工具。这个配置可能在浏览器中不能使用,Web 页面更不用说(通过 HTTP 标头,等等)。 + +```bash +node --max-old-space-size=6000 index.js +``` + +使用标志和 [Chrome Debugger](https://nodejs.org/en/learn/getting-started/debugging) 也能为出错内存问题暴露垃圾回收器: + +```bash +node --expose-gc --inspect index.js +``` + +## 帮助内存管理的数据结构 + +尽管 JavaScript 没有直接暴露垃圾回收器 API。但语言提供几个间接观察垃圾回收的数据结构,能用于内存管理。 + +### WeakMap 和 WeakSet + +[`WeakMap`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) 和 [`WeakSet`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) 的 API 几乎镜像非 weak 版的:[`Map`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map) 和 [`Set`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set)。`WeakMap` 维护一个键-值对的集合,而 `WeakSet` 维护一个唯一值的集合,两者都能高效的添加、删除和查询。 + +`WeakMap` 和 `WeakSet` 的名字来源于*弱引用*值的概念。假设 `x` 被 `y`弱引用,这意味着尽管你能通过 `y` 访问 `x`的值,但如果 `x` 不再被*强引用*的话,标记清除算法不会认为 `x` 是可达的。大多数数据结构,除了在这讨论的这两个,都是强引用传入的对象,这样你才能在任意时间取回这些对象。只要程序中不再有键的引用,`WeakMap` 和 `WeakSet` 的键能被垃圾回收(对 `WeakMap` 对象,值接着也适合被回收)。这一点由两个特性确保: + +- `WeakMap` 和 `WeakSet` 仅能存储对象或 symbol。这是因为仅对象是可垃圾回收的——原始值总是被复制的(也就是,`1 === 1` 但 `{} !== {}`),这让原始值永远呆在集合中。[已注册的 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry)(如 `Symbol.for("key")`)也是被复制,因此也不是可垃圾回收的,但是用 `Symbol("key")` 创建的 symbol 是可垃圾回收的。[内置通用 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#well-known_symbols)(如 `Symbol.iterator`)来自于一组固定的集合,在程序的整个声明周期中是唯一的,类似于雇固有的对象(如 `Array.prototype`),所以它们也能作为键。 +- `WeakMap` 和 `WeakSet` 是不可迭代的。这禁止你使用 `Array.from(map.keys()).length` 观察对象的存活性或获取任意适合垃圾回收的键的引用(垃圾回收应尽可能不可见)。 + +在典型的 `WeakMap` 和 `WeakSet` 的解释中(就像上面那样),通常暗示,键首先被垃圾回收,然后值也被垃圾回收。然而,考虑值引用键这个例子: + +```js +const wm = new WeakMap(); +const key = {}; +wm.set(key, { key }); +// 现在 `key` 不能被垃圾回收, +// 因为值引用了键, +// 并且值在 map 中是强引用! +``` + +假设 `key` 存储为真实的引用,它将创建一个循环引用,让键和值都不适合垃圾回收,即使在 `key` 没有被引用时——因为假设 `key` 被垃圾回收了,这意味着在某个特定的时刻,`value.key` 将指向一个不存在的地址,而这是非法的。为了修复这个,`WeakMap` 和 `WeakSet` 的条目不是真正的引用,而是 [临时对象](https://dl.acm.org/doi/pdf/10.1145/263700.263733),对标记清除机制的增强。[Barros et al.](https://www.jucs.org/jucs_14_21/eliminating_cycles_in_weak/jucs_14_21_3481_3497_barros.pdf) 对算法提供了一个很好的总结(第 4 页)。引用一段: + +> 临时对象是 weak pairs 的改进,在 pairs 中,键和值都不分类为弱或强。键的连接性决定了值的连接性,但值的连接性不会影响键的连接性。[...]当垃圾回收提供临时对象的支持时,它会出现三个阶段而不是两个(标记和清除)。 + +作为一个粗糙但走心的模型,将下列的实现当作 `WeakMap` 的实现: -IE 6, 7 使用引用计数方式对 DOM 对象进行垃圾回收。该方式常常造成对象被循环引用时内存发生泄漏: +> [!WARNING] +> 这不是 polyfill,也不接近引擎中的实现(引擎中的实现 hook 进了垃圾回收机制)。 ```js -var div; -window.onload = function () { - div = document.getElementById("myDivElement"); - div.circularReference = div; - div.lotsOfData = new Array(10000).join("*"); -}; +class MyWeakMap { + #marker = Symbol("MyWeakMapData"); + get(key) { + return key[this.#marker]; + } + set(key, value) { + key[this.#marker] = value; + } + has(key) { + return this.#marker in key; + } + delete(key) { + delete key[this.#marker]; + } +} ``` -在上面的例子里,`myDivElement` 这个 DOM 元素里的 `circularReference 属性`引用了 `myDivElement`,造成了循环引用。如果该属性没有显示移除或者设为 null,引用计数式垃圾收集器将总是且至少有一个引用,并将一直保持在内存里的 DOM 元素,即使其从 DOM 树中删去了。如果这个 DOM 元素拥有大量的数据 (如上的 `lotsOfData` 属性),而这个数据占用的内存将永远不会被释放。 +正如你所看到的,`MyWeakMap` 实际上永远没有保存一个键集合。它简单地将元数据添加到传入的每个对象中。对象接着通过标记清除被垃圾回收。因此,在 `WeakMap` 上进行迭代是不可能的,清除 `WeakMap` 也是不可能的(因为那也依赖于完整的键集合信息)。 + +更多有关它们的 API 的信息,参见[带键的集合](/zh-CN/docs/Web/JavaScript/Guide/Keyed_collections)指南。 -### 标记 - 清除算法 +### WeakRefs 和 FinalizationRegistry -这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。 +> **Note:** `WeakRef` 和 `FinalizationRegistry` 能直接内省进垃圾回收机制。[尽量避免使用](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#avoid_where_possible)因为运行时语义几乎完全不受保证。 -这个算法假定设置一个叫做根(root)的对象(在 Javascript 里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。 -这个算法比前一个要好,因为“有零引用的对象”总是不可获得的,但是相反却不一定,参考“循环引用”。 +所有用对象作为值的变量都是那个对象的引用。然而,这样的引用是*强引用*——它们的存在会阻止垃圾回收器将对象标记为适合回收。[`WeakRef`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) 是对象的*弱引用*,这让对象能被垃圾回收,同时在对象的声明周期期间仍保留了读取对象的内容的能力。 -从 2012 年起,所有现代浏览器都使用了标记 - 清除垃圾回收算法。所有对 JavaScript 垃圾回收算法的改进都是基于标记 - 清除算法的改进,并没有改进标记 - 清除算法本身和它对“对象是否不再需要”的简化定义。 +一个 `WeakRef` 用例是将字符串 URL 映射为大对象的缓存系统。这个缓存系统我们不能使用 `WeakMap`。因为 `WeakMap` 对象的*键*是弱引用的,而不是*值*——如果你访问键,你将总是确定地得到值(因为能访问键意味着键仍然有效)。这里,从键得到的是 `undefined` 是没问题的(如果对应的值不再有效),因为我们只需要重新计算,但是我们不想让不可达的对象呆在缓存中。在这个例子中,我们使用普通的 `Map`,但是值使用 `WeakRef` 对象,而不是真正的对象值。 + +```js +function cached(getter) { + // 一个 Map:从字符串 URL 到结果的 WeakRef + const cache = new Map(); + return async (key) => { + if (cache.has(key)) { + const dereferencedValue = cache.get(key).deref(); + if (dereferencedValue !== undefined) { + return dereferencedValue; + } + } + const value = await getter(key); + cache.set(key, new WeakRef(value)); + return value; + }; +} -#### 循环引用不再是问题了 +const getImage = cached((url) => fetch(url).then((res) => res.blob())); +``` -在上面的示例中,函数调用返回之后,两个对象从全局对象出发无法获取。因此,他们将会被垃圾回收器回收。第二个示例同样,一旦 div 和其事件处理无法从根获取到,他们将会被垃圾回收器回收。 +[`FinalizationRegistry`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) 提供了一个更强的机制观察垃圾回收。它让你注册对象以及对象被垃圾回收时得到通知。例如,对于上面的缓存系统这个例子,即使在 blob 自身被垃圾回收时,引用 blob 的 `WeakRef` 对象不会被垃圾回收——随着时间的积累,`Map` 可能积聚大量的无用条目。在这里例子中,使用 `FinalizationRegistry` 能执行清除。 -#### 限制:那些无法从根对象查询到的对象都将被清除 +```js +function cached(getter) { + // 一个 Map:从字符串 URL 到结果的 WeakRef + const cache = new Map(); + // 每次值被垃圾回收之后,用缓存中的 key 作为参数调用回调,能移除缓存条目 + const registry = new FinalizationRegistry((key) => { + // 注意:测试 WeakRef 真的为空很重要。否则,回调可能在用这个 key 添加新对象之后调用,然后那个新的、有效的对象就被删除了 + if (!cache.get(key)?.deref()) { + cache.delete(key); + } + }); + return async (key) => { + if (cache.has(key)) { + return cache.get(key).deref(); + } + const value = await getter(key); + cache.set(key, new WeakRef(value)); + registry.register(value, key); + return value; + }; +} -尽管这是一个限制,但实践中我们很少会碰到类似的情况,所以开发者不太会去关心垃圾回收机制。 +const getImage = cached((url) => fetch(url).then((res) => res.blob())); +``` -## 参考 +出于性能和安全考虑,不会保证何时调用回调,或者是否会调用。它应该仅用于清除——非关键的清除。有其他更确定的资源管理的方式,例如 [`try...finally`](/zh-CN/docs/Web/JavaScript/Reference/Statements/try...catch),总是会执行 `finally` 块。`WeakRef` 和 `FinalizationRegistry` 仅用于长时间运行的程序中的内存用量优化。 -- [IBM article on "Memory leak patterns in JavaScript" (2007)](http://www.ibm.com/developerworks/web/library/wa-memleak/) -- [Kangax article on how to register event handler and avoid memory leaks (2010)](http://msdn.microsoft.com/en-us/magazine/ff728624.aspx) -- [Performance](/zh-CN/docs/Mozilla/Performance) +更多有关 [`WeakRef`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) and [`FinalizationRegistry`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) 的 API 的信息,参见对应的参考页面。 From b903882eb18ff5cd6905f87abf7ea03c4da051ca Mon Sep 17 00:00:00 2001 From: familyboat <2015301110129@whu.edu.cn> Date: Tue, 29 Oct 2024 15:38:48 +0800 Subject: [PATCH 02/27] =?UTF-8?q?=E9=93=BE=E6=8E=A5=E5=92=8C=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/javascript/memory_management/index.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 18c45bad2b42ca..30de4f42fc9b49 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -7,7 +7,7 @@ l10n: {{JsSidebar("Advanced")}} -底层语言(如 c 语言)拥有手动的内存管理基本操作,例如:[`malloc()`](https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) 和 [`free()`](https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Overview_of_functions)。相反,JavaScript 是在创建对象时自动分配内存,并在不再使用时自动释放内存(*垃圾回收*)。这个自动性是混乱的潜在根源:它让开发者错误地以为他们不需要担心内存管理。 +底层语言(如 C 语言)拥有手动的内存管理基本操作,例如:[`malloc()`](https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) 和 [`free()`](https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Overview_of_functions)。相反,JavaScript 是在创建对象时自动分配内存,并在不再使用时自动释放内存(*垃圾回收*)。这个自动性是混乱的潜在根源:它让开发者错误地以为他们不需要担心内存管理。 ## 内存生命周期 @@ -90,11 +90,11 @@ const a3 = a.concat(a2); ## 垃圾回收 -如上文所述,自动寻找一些内存是否“不再需要”这个一般性问题是无法判定的。因此,垃圾回收器对这个一般性问题实现了一个存在限制的解决方案。本节将解释理解主要的垃圾回收算法及其相应的局限所必须的概念。 +如上文所述,自动寻找一些内存是否“不再需要”这个一般性问题是无法判定的。因此,垃圾回收器对这个一般性问题实现了一个存在限制的解决方案。本节将解释理解主要的垃圾回收算法及其对应的局限所必须的概念。 ### 引用 -垃圾回收算法依赖的主要概念是引用。在内存管理的上下文中,如果一个对象有访问另一个对象的权限(隐式或者显式),称作前面的对象引用后面的对象。例如,一个 Javascript 对象具有对它的[原型](/zh-CN/JavaScript/Guide/Inheritance_and_the_prototype_chain)的引用(隐式引用)和对它属性的引用(显式引用)。 +垃圾回收算法依赖的主要概念是引用。在内存管理的上下文中,如果一个对象有访问另一个对象的权限(隐式或者显式),称作前面的对象引用后面的对象。例如,一个 JavaScript 对象具有对它的[原型](/zh-CN/JavaScript/Guide/Inheritance_and_the_prototype_chain)的引用(隐式引用)和对它属性的引用(显式引用)。 在这个上下文中,“对象”的概念不仅指常规的 JavaScript 对象,还包括函数作用域(或者全局词法作用域)。 @@ -155,25 +155,25 @@ f(); 这个算法将“对象不再需要”这个定义简化为“对象不可达”。 -这个算法假定有一组叫做*根*的对象。在 Javascript 中,根是全局对象。垃圾回收器将定期从这些根开始,找到从这些根能引用到的所有对象,然后找到从这些对象能引用到的所有对象,等等。从根开始,垃圾回收器将找到所有可以到达的对象并收集所有不能到达的对象。 +这个算法假定有一组叫做*根*的对象。在 JavaScript 中,根是全局对象。垃圾回收器将定期从这些根开始,找到从这些根能引用到的所有对象,然后找到从这些对象能引用到的所有对象,等等。从根开始,垃圾回收器将找到所有可以到达的对象并收集所有不能到达的对象。 这个算法是对上一个算法的改进。因为对于引用计数算法,有零引用的对象实际上是不可达的,但是有引用的对象却不一定,就像在循环引用中看到的那样。 -当前,所有现代的引擎搭载的是标记清除垃圾回收器。过去几年中,在 JavaScript 垃圾回收领域做出的改进(分代/增量/并发/并行 垃圾回收)都是这个算法的实现改进,而不是垃圾回收算法本身的改进,也不是何时“对象不再需要”这个定义的简化。 +当前,所有现代的引擎搭载的是标记清除垃圾回收器。过去几年中,在 JavaScript 垃圾回收领域做出的改进(分代/增量/并发/并行垃圾回收)都是这个算法的实现改进,而不是垃圾回收算法本身的改进,也不是何时“对象不再需要”这个定义的简化。 这个方法的直接好处就是循环不再是一个问题。在上面的示例中,在函数调用返回之后,从全局对象可达的任何资源都将不再引用这两个对象。因此,垃圾回收器会认为它们不可达并回收为它们分配的内存。 -然而,手动控制垃圾回收的能力仍不存在。有时候动手决定何时释放内存以及释放哪块内存会很方便。为了释放对象的内存,需要显式地变成不可达。在 JavaScript 中,编程式地触发垃圾回收也不可能——永不可能出现在核心语言中,尽管引擎可能在可选的标志中暴露了相关的 API。 +然而,手动控制垃圾回收的能力仍不存在。有时候手动决定何时释放内存以及释放哪块内存会很方便。为了释放对象的内存,需要显式地变成不可达。在 JavaScript 中,编程式地触发垃圾回收也不可能——永不可能出现在核心语言中,尽管引擎可能在可选的标志中暴露了相关的 API。 ## 配置引擎的内存模型 -JavaScript 引擎典型地提供了暴露内存模型地标志。例如,Node.js 为配置和除错内存问题提供了暴露底层的 V8 机制的额外选项和工具。这个配置可能在浏览器中不能使用,Web 页面更不用说(通过 HTTP 标头,等等)。 +JavaScript 引擎典型地提供了暴露内存模型地标志。例如,Node.js 为配置和调试内存问题提供了暴露底层的 V8 机制的额外选项和工具。这个配置可能在浏览器中不能使用,Web 页面更不用说(通过 HTTP 标头,等等)。 ```bash node --max-old-space-size=6000 index.js ``` -使用标志和 [Chrome Debugger](https://nodejs.org/en/learn/getting-started/debugging) 也能为出错内存问题暴露垃圾回收器: +使用标志和 [Chrome 调试器](https://nodejs.org/en/learn/getting-started/debugging) 也能为调试内存问题暴露垃圾回收器: ```bash node --expose-gc --inspect index.js @@ -189,7 +189,7 @@ node --expose-gc --inspect index.js `WeakMap` 和 `WeakSet` 的名字来源于*弱引用*值的概念。假设 `x` 被 `y`弱引用,这意味着尽管你能通过 `y` 访问 `x`的值,但如果 `x` 不再被*强引用*的话,标记清除算法不会认为 `x` 是可达的。大多数数据结构,除了在这讨论的这两个,都是强引用传入的对象,这样你才能在任意时间取回这些对象。只要程序中不再有键的引用,`WeakMap` 和 `WeakSet` 的键能被垃圾回收(对 `WeakMap` 对象,值接着也适合被回收)。这一点由两个特性确保: -- `WeakMap` 和 `WeakSet` 仅能存储对象或 symbol。这是因为仅对象是可垃圾回收的——原始值总是被复制的(也就是,`1 === 1` 但 `{} !== {}`),这让原始值永远呆在集合中。[已注册的 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry)(如 `Symbol.for("key")`)也是被复制,因此也不是可垃圾回收的,但是用 `Symbol("key")` 创建的 symbol 是可垃圾回收的。[内置通用 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#well-known_symbols)(如 `Symbol.iterator`)来自于一组固定的集合,在程序的整个声明周期中是唯一的,类似于雇固有的对象(如 `Array.prototype`),所以它们也能作为键。 +- `WeakMap` 和 `WeakSet` 仅能存储对象或 symbol。这是因为仅对象是可垃圾回收的——原始值总是被复制的(也就是,`1 === 1` 但 `{} !== {}`),这让原始值永远呆在集合中。[已注册的 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry)(如 `Symbol.for("key")`)也是被复制,因此也不是可垃圾回收的,但是用 `Symbol("key")` 创建的 symbol 是可垃圾回收的。[内置通用 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#内置通用(well-known)symbol)(如 `Symbol.iterator`)来自于一组固定的集合,在程序的整个声明周期中是唯一的,类似于雇固有的对象(如 `Array.prototype`),所以它们也能作为键。 - `WeakMap` 和 `WeakSet` 是不可迭代的。这禁止你使用 `Array.from(map.keys()).length` 观察对象的存活性或获取任意适合垃圾回收的键的引用(垃圾回收应尽可能不可见)。 在典型的 `WeakMap` 和 `WeakSet` 的解释中(就像上面那样),通常暗示,键首先被垃圾回收,然后值也被垃圾回收。然而,考虑值引用键这个例子: @@ -236,7 +236,7 @@ class MyWeakMap { ### WeakRefs 和 FinalizationRegistry -> **Note:** `WeakRef` 和 `FinalizationRegistry` 能直接内省进垃圾回收机制。[尽量避免使用](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#avoid_where_possible)因为运行时语义几乎完全不受保证。 +> **Note:** `WeakRef` 和 `FinalizationRegistry` 能直接内省进垃圾回收机制。[尽量避免使用](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#尽量避免使用)因为运行时语义几乎完全不受保证。 所有用对象作为值的变量都是那个对象的引用。然而,这样的引用是*强引用*——它们的存在会阻止垃圾回收器将对象标记为适合回收。[`WeakRef`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) 是对象的*弱引用*,这让对象能被垃圾回收,同时在对象的声明周期期间仍保留了读取对象的内容的能力。 From a0a3cde2c6c3eb95326e014289dff15629ab2199 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:47:08 +0800 Subject: [PATCH 03/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 30de4f42fc9b49..3716b7527debb5 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -203,7 +203,7 @@ wm.set(key, { key }); // 并且值在 map 中是强引用! ``` -假设 `key` 存储为真实的引用,它将创建一个循环引用,让键和值都不适合垃圾回收,即使在 `key` 没有被引用时——因为假设 `key` 被垃圾回收了,这意味着在某个特定的时刻,`value.key` 将指向一个不存在的地址,而这是非法的。为了修复这个,`WeakMap` 和 `WeakSet` 的条目不是真正的引用,而是 [临时对象](https://dl.acm.org/doi/pdf/10.1145/263700.263733),对标记清除机制的增强。[Barros et al.](https://www.jucs.org/jucs_14_21/eliminating_cycles_in_weak/jucs_14_21_3481_3497_barros.pdf) 对算法提供了一个很好的总结(第 4 页)。引用一段: +假设 `key` 存储为真实的引用,它将创建一个循环引用,让键和值都不适合垃圾回收,即使在 `key` 没有被引用时——因为假设 `key` 被垃圾回收了,这意味着在某个特定的时刻,`value.key` 将指向一个不存在的地址,而这是非法的。为了修复这个,`WeakMap` 和 `WeakSet` 的条目不是真正的引用,而是 [临时对象](https://dl.acm.org/doi/pdf/10.1145/263700.263733),对标记清除机制的增强。[Barros et al.](https://www.jucs.org/jucs_14_21/eliminating_cycles_in_weak/jucs_14_21_3481_3497_barros.pdf) 对算法提供了一个很好的总结(第 4 页)。引用一段: > 临时对象是 weak pairs 的改进,在 pairs 中,键和值都不分类为弱或强。键的连接性决定了值的连接性,但值的连接性不会影响键的连接性。[...]当垃圾回收提供临时对象的支持时,它会出现三个阶段而不是两个(标记和清除)。 From c22b4c984bd17ddcf66dcae5b7783c86919638d3 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:47:18 +0800 Subject: [PATCH 04/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 3716b7527debb5..78d00a238bb733 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -238,7 +238,6 @@ class MyWeakMap { > **Note:** `WeakRef` 和 `FinalizationRegistry` 能直接内省进垃圾回收机制。[尽量避免使用](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#尽量避免使用)因为运行时语义几乎完全不受保证。 - 所有用对象作为值的变量都是那个对象的引用。然而,这样的引用是*强引用*——它们的存在会阻止垃圾回收器将对象标记为适合回收。[`WeakRef`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) 是对象的*弱引用*,这让对象能被垃圾回收,同时在对象的声明周期期间仍保留了读取对象的内容的能力。 一个 `WeakRef` 用例是将字符串 URL 映射为大对象的缓存系统。这个缓存系统我们不能使用 `WeakMap`。因为 `WeakMap` 对象的*键*是弱引用的,而不是*值*——如果你访问键,你将总是确定地得到值(因为能访问键意味着键仍然有效)。这里,从键得到的是 `undefined` 是没问题的(如果对应的值不再有效),因为我们只需要重新计算,但是我们不想让不可达的对象呆在缓存中。在这个例子中,我们使用普通的 `Map`,但是值使用 `WeakRef` 对象,而不是真正的对象值。 From fd737b67a487a6cbcc842a35e5ec1e3eb185d2ef Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:47:31 +0800 Subject: [PATCH 05/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 78d00a238bb733..85e4bdb1e70269 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -185,7 +185,7 @@ node --expose-gc --inspect index.js ### WeakMap 和 WeakSet -[`WeakMap`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) 和 [`WeakSet`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) 的 API 几乎镜像非 weak 版的:[`Map`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map) 和 [`Set`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set)。`WeakMap` 维护一个键-值对的集合,而 `WeakSet` 维护一个唯一值的集合,两者都能高效的添加、删除和查询。 +[`WeakMap`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) 和 [`WeakSet`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) 的 API 几乎镜像非 weak 版的:[`Map`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map) 和 [`Set`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set)。`WeakMap` 维护一个键 - 值对的集合,而 `WeakSet` 维护一个唯一值的集合,两者都能高效的添加、删除和查询。 `WeakMap` 和 `WeakSet` 的名字来源于*弱引用*值的概念。假设 `x` 被 `y`弱引用,这意味着尽管你能通过 `y` 访问 `x`的值,但如果 `x` 不再被*强引用*的话,标记清除算法不会认为 `x` 是可达的。大多数数据结构,除了在这讨论的这两个,都是强引用传入的对象,这样你才能在任意时间取回这些对象。只要程序中不再有键的引用,`WeakMap` 和 `WeakSet` 的键能被垃圾回收(对 `WeakMap` 对象,值接着也适合被回收)。这一点由两个特性确保: From f0d69ab9fe1a75ee1e7078f7f7fb1bad8b56b194 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:47:41 +0800 Subject: [PATCH 06/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 85e4bdb1e70269..f58db66c41bdd5 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -7,7 +7,7 @@ l10n: {{JsSidebar("Advanced")}} -底层语言(如 C 语言)拥有手动的内存管理基本操作,例如:[`malloc()`](https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) 和 [`free()`](https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Overview_of_functions)。相反,JavaScript 是在创建对象时自动分配内存,并在不再使用时自动释放内存(*垃圾回收*)。这个自动性是混乱的潜在根源:它让开发者错误地以为他们不需要担心内存管理。 +底层语言(如 C 语言)拥有手动的内存管理基本操作,例如:[`malloc()`](https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) 和 [`free()`](https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Overview_of_functions)。相反,JavaScript 是在创建对象时自动分配内存,并在不再使用时自动释放内存(_垃圾回收_)。这个自动性是混乱的潜在根源:它让开发者错误地以为他们不需要担心内存管理。 ## 内存生命周期 From 3b0f8b443f8032f7ec10472385685ee1f4476eb3 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Tue, 29 Oct 2024 17:15:50 +0800 Subject: [PATCH 07/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Yanko1013 --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index f58db66c41bdd5..b13cbd5d4ffb62 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -291,4 +291,4 @@ const getImage = cached((url) => fetch(url).then((res) => res.blob())); 出于性能和安全考虑,不会保证何时调用回调,或者是否会调用。它应该仅用于清除——非关键的清除。有其他更确定的资源管理的方式,例如 [`try...finally`](/zh-CN/docs/Web/JavaScript/Reference/Statements/try...catch),总是会执行 `finally` 块。`WeakRef` 和 `FinalizationRegistry` 仅用于长时间运行的程序中的内存用量优化。 -更多有关 [`WeakRef`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) and [`FinalizationRegistry`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) 的 API 的信息,参见对应的参考页面。 +更多有关 [`WeakRef`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) 和 [`FinalizationRegistry`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) 的 API 的信息,参见对应的参考页面。 From b2417687db713d396cf2575b3468dba6be1d0253 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:35:07 +0800 Subject: [PATCH 08/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index b13cbd5d4ffb62..0f61852e7446dd 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -2,7 +2,7 @@ title: 内存管理 slug: Web/JavaScript/Memory_management l10n: - sourceCommit: e03b13c7e157ec7b7bb02a6c7c4854b862195905 + sourceCommit: 2c762771070a207d410a963166adf32213bc3a45 --- {{JsSidebar("Advanced")}} From b2a14d19e5fda0f588c7b56d89b1643f5b78b33c Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:35:55 +0800 Subject: [PATCH 09/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 0f61852e7446dd..9742c021cba205 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -7,7 +7,7 @@ l10n: {{JsSidebar("Advanced")}} -底层语言(如 C 语言)拥有手动的内存管理基本操作,例如:[`malloc()`](https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) 和 [`free()`](https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Overview_of_functions)。相反,JavaScript 是在创建对象时自动分配内存,并在不再使用时自动释放内存(_垃圾回收_)。这个自动性是混乱的潜在根源:它让开发者错误地以为他们不需要担心内存管理。 +底层语言(如 C 语言)拥有手动的内存管理原语,例如:[`malloc()`](https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html) 和 [`free()`](https://zh.wikipedia.org/wiki/C动态内存分配#函数概述)。相反,JavaScript 是在创建对象时自动分配内存,并在不再使用时自动释放内存(_垃圾回收_)。这个自动性是混乱的潜在根源:它让开发者错误地以为他们不需要担心内存管理。 ## 内存生命周期 From e0f5eb46853551a497a33f538c81bc2a407db428 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:36:09 +0800 Subject: [PATCH 10/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 9742c021cba205..98767d5ac790ee 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -15,7 +15,7 @@ l10n: 1. 分配你所需要的内存 2. 使用分配到的内存(读、写) -3. 不需要时将其释放\归还 +3. 不需要时将其释放 在所有语言中,第二点都是显式的。在底层语言中,第一点和第三点是显式的,但在高级语言中(如 JavaScript),大多数是隐式的。 From 2e3acca95776358cc87c2c53116dafb596fc12ff Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:36:31 +0800 Subject: [PATCH 11/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 98767d5ac790ee..36ce03b4943985 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -26,7 +26,7 @@ l10n: 为了不让程序员费心内存分配,JavaScript 在值初次声明时自动分配内存。 ```js -const n = 123; // 为数字分配内存 +const n = 123; // 为数值分配内存 const s = "azerty"; // 为字符串分配内存 const o = { From 40950c02144ff82ad4e221827ce459615af119cd Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:36:53 +0800 Subject: [PATCH 12/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 36ce03b4943985..eeddeb896cfb75 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -70,8 +70,8 @@ const s2 = s.substr(0, 3); // s2 是一个新的字符串 // JavaScript 可能决定不分配内存, // 只是存储了 [0-3] 的范围。 -const a = ["ouais ouais", "nan nan"]; -const a2 = ["generation", "nan nan"]; +const a = ["yeah yeah", "no no"]; +const a2 = ["generation", "no no"]; const a3 = a.concat(a2); // 有四个元素的新数组,由 a 和 a2 元素连接而成。 ``` From e72a973f9b042d98c96e3cffe1f57cf9589e5c98 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:37:22 +0800 Subject: [PATCH 13/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index eeddeb896cfb75..d41e7535ed80b9 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -73,7 +73,7 @@ const s2 = s.substr(0, 3); // s2 是一个新的字符串 const a = ["yeah yeah", "no no"]; const a2 = ["generation", "no no"]; const a3 = a.concat(a2); -// 有四个元素的新数组,由 a 和 a2 元素连接而成。 +// 有四个元素的新数组,由 a 和 a2 其中的元素连接而成。 ``` ### 使用值 From 59b095463a6925042173c0964ed4b32a67233aff Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:37:42 +0800 Subject: [PATCH 14/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index d41e7535ed80b9..ebe906bb2207c7 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -78,7 +78,7 @@ const a3 = a.concat(a2); ### 使用值 -使用值基本上是指在分配的内存上进行读写。读写变量值或对象的属性值、甚至给函数传递参数都会使用值。 +使用值基本上是指在分配的内存上进行读写。读写变量值或对象的属性值,甚至给函数传递参数都会使用值。 ### 当内存不再需要使用时释放 From 4354efa8d1f6a570463ee19df08273b2d1e5d792 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:38:04 +0800 Subject: [PATCH 15/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index ebe906bb2207c7..99c973f437d17e 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -86,7 +86,7 @@ const a3 = a.concat(a2); 底层语言要求开发人员手动确定在程序的哪个点不再需要已分配的内存并释放这块内存。 -一些高级语言(如 JavaScript)使用的是自动内存管理(也就是[垃圾回收]()(GC))的形式。垃圾回收器的目的是监控内存分配和确定一块已分配的内存何时不再需要并释放这块内存。这个自动过程是个近似的说法,因为确定一块特定的内存是否仍然需要这个一般性问题是[无法判定的](http://en.wikipedia.org/wiki/Decidability_%28logic%29)。 +一些高级语言(如 JavaScript)使用的是自动内存管理(也就是[垃圾回收]()(GC))的形式。垃圾回收器的目的是监控内存分配和确定一块已分配的内存何时不再需要并释放这块内存。这个自动过程是个近似的说法,因为确定一块特定的内存是否仍然需要这个一般性问题是[无法判定的](http://en.wikipedia.org/wiki/Decidability_%28logic%29)。 ## 垃圾回收 From 81f4695c0b4823b05cabe1288a8a09b77f90cabc Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:38:40 +0800 Subject: [PATCH 16/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 99c973f437d17e..f5796b96a4d708 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -101,7 +101,7 @@ const a3 = a.concat(a2); ### 引用计数垃圾回收 > [!NOTE] -> 现代的浏览器不再使用引用计数进行垃圾回收。 +> 现代 JavaScript 引擎不再使用引用计数进行垃圾回收。 这是最初级的垃圾回收算法。此算法把确定对象是否仍然需要这个问题简化为确定对象是否仍有其他引用它的对象。如果没有指向该对象的引用,那么该对象称作“垃圾”或者可回收的。 From 78d869556885f14c543c837a2caa9bf2403afa78 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:39:21 +0800 Subject: [PATCH 17/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index f5796b96a4d708..711263fa110569 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -155,7 +155,7 @@ f(); 这个算法将“对象不再需要”这个定义简化为“对象不可达”。 -这个算法假定有一组叫做*根*的对象。在 JavaScript 中,根是全局对象。垃圾回收器将定期从这些根开始,找到从这些根能引用到的所有对象,然后找到从这些对象能引用到的所有对象,等等。从根开始,垃圾回收器将找到所有可以到达的对象并收集所有不能到达的对象。 +这个算法假定有一组叫做*根*的对象。在 JavaScript 中,根是全局对象。垃圾回收器将定期从这些根开始,找到从这些根能引用到的所有对象,然后找到从这些对象能引用到的所有对象,等等。从根开始,垃圾回收器将找到所有*可到达*的对象并收集所有不能到达的对象。 这个算法是对上一个算法的改进。因为对于引用计数算法,有零引用的对象实际上是不可达的,但是有引用的对象却不一定,就像在循环引用中看到的那样。 From 1504a52179a4f36b38f526545a86ead734b6981a Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:39:48 +0800 Subject: [PATCH 18/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 711263fa110569..6f685cce7bde1d 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -168,6 +168,7 @@ f(); ## 配置引擎的内存模型 JavaScript 引擎典型地提供了暴露内存模型地标志。例如,Node.js 为配置和调试内存问题提供了暴露底层的 V8 机制的额外选项和工具。这个配置可能在浏览器中不能使用,Web 页面更不用说(通过 HTTP 标头,等等)。 +最大可用堆内存可以通过使用标志来增加: ```bash node --max-old-space-size=6000 index.js From 6a4bdc87e91d46f12de5300ae0586a1d649ed5e3 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:40:37 +0800 Subject: [PATCH 19/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 6f685cce7bde1d..7a29f894c21db7 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -188,7 +188,7 @@ node --expose-gc --inspect index.js [`WeakMap`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) 和 [`WeakSet`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) 的 API 几乎镜像非 weak 版的:[`Map`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map) 和 [`Set`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set)。`WeakMap` 维护一个键 - 值对的集合,而 `WeakSet` 维护一个唯一值的集合,两者都能高效的添加、删除和查询。 -`WeakMap` 和 `WeakSet` 的名字来源于*弱引用*值的概念。假设 `x` 被 `y`弱引用,这意味着尽管你能通过 `y` 访问 `x`的值,但如果 `x` 不再被*强引用*的话,标记清除算法不会认为 `x` 是可达的。大多数数据结构,除了在这讨论的这两个,都是强引用传入的对象,这样你才能在任意时间取回这些对象。只要程序中不再有键的引用,`WeakMap` 和 `WeakSet` 的键能被垃圾回收(对 `WeakMap` 对象,值接着也适合被回收)。这一点由两个特性确保: +`WeakMap` 和 `WeakSet` 的名字来源于*弱引用*值的概念。假设 `x` 被 `y` 弱引用,这意味着尽管你能通过 `y` 访问 `x` 的值,但如果 `x` 不再被*强引用*的话,标记清除算法不会认为 `x` 是可达的。大多数数据结构,除了在这讨论的这两个,都是强引用传入的对象,这样你才能在任意时间取回这些对象。只要程序中不再有键的引用,`WeakMap` 和 `WeakSet` 的键能被垃圾回收(对 `WeakMap` 对象,值接着也适合被回收)。这一点由两个特性确保: - `WeakMap` 和 `WeakSet` 仅能存储对象或 symbol。这是因为仅对象是可垃圾回收的——原始值总是被复制的(也就是,`1 === 1` 但 `{} !== {}`),这让原始值永远呆在集合中。[已注册的 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry)(如 `Symbol.for("key")`)也是被复制,因此也不是可垃圾回收的,但是用 `Symbol("key")` 创建的 symbol 是可垃圾回收的。[内置通用 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#内置通用(well-known)symbol)(如 `Symbol.iterator`)来自于一组固定的集合,在程序的整个声明周期中是唯一的,类似于雇固有的对象(如 `Array.prototype`),所以它们也能作为键。 - `WeakMap` 和 `WeakSet` 是不可迭代的。这禁止你使用 `Array.from(map.keys()).length` 观察对象的存活性或获取任意适合垃圾回收的键的引用(垃圾回收应尽可能不可见)。 From 44cdc95ca3adebf14daf1344a820a12d89e7ab52 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:41:13 +0800 Subject: [PATCH 20/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 7a29f894c21db7..2c5207a5300a3b 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -190,7 +190,7 @@ node --expose-gc --inspect index.js `WeakMap` 和 `WeakSet` 的名字来源于*弱引用*值的概念。假设 `x` 被 `y` 弱引用,这意味着尽管你能通过 `y` 访问 `x` 的值,但如果 `x` 不再被*强引用*的话,标记清除算法不会认为 `x` 是可达的。大多数数据结构,除了在这讨论的这两个,都是强引用传入的对象,这样你才能在任意时间取回这些对象。只要程序中不再有键的引用,`WeakMap` 和 `WeakSet` 的键能被垃圾回收(对 `WeakMap` 对象,值接着也适合被回收)。这一点由两个特性确保: -- `WeakMap` 和 `WeakSet` 仅能存储对象或 symbol。这是因为仅对象是可垃圾回收的——原始值总是被复制的(也就是,`1 === 1` 但 `{} !== {}`),这让原始值永远呆在集合中。[已注册的 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry)(如 `Symbol.for("key")`)也是被复制,因此也不是可垃圾回收的,但是用 `Symbol("key")` 创建的 symbol 是可垃圾回收的。[内置通用 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#内置通用(well-known)symbol)(如 `Symbol.iterator`)来自于一组固定的集合,在程序的整个声明周期中是唯一的,类似于雇固有的对象(如 `Array.prototype`),所以它们也能作为键。 +- `WeakMap` 和 `WeakSet` 仅能存储对象或 symbol。这是因为仅对象是可垃圾回收的——原始值总是被复制的(也就是,`1 === 1` 但 `{} !== {}`),这让原始值永远呆在集合中。[已注册的 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#shared_symbols_in_the_global_symbol_registry)(如 `Symbol.for("key")`)也是被复制,因此也不是可垃圾回收的,但是用 `Symbol("key")` 创建的 symbol 是可垃圾回收的。[内置通用 symbol](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol#内置通用(well-known)symbol)(如 `Symbol.iterator`)来自于一组固定的集合,在程序的整个声明周期中是唯一的,类似于固有对象(如 `Array.prototype`),所以它们也能作为键。 - `WeakMap` 和 `WeakSet` 是不可迭代的。这禁止你使用 `Array.from(map.keys()).length` 观察对象的存活性或获取任意适合垃圾回收的键的引用(垃圾回收应尽可能不可见)。 在典型的 `WeakMap` 和 `WeakSet` 的解释中(就像上面那样),通常暗示,键首先被垃圾回收,然后值也被垃圾回收。然而,考虑值引用键这个例子: From 1b12863fd92f946b8b34ca1569a724b3e79a8f2a Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:43:02 +0800 Subject: [PATCH 21/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 2c5207a5300a3b..f3b60ce6dd1576 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -204,7 +204,7 @@ wm.set(key, { key }); // 并且值在 map 中是强引用! ``` -假设 `key` 存储为真实的引用,它将创建一个循环引用,让键和值都不适合垃圾回收,即使在 `key` 没有被引用时——因为假设 `key` 被垃圾回收了,这意味着在某个特定的时刻,`value.key` 将指向一个不存在的地址,而这是非法的。为了修复这个,`WeakMap` 和 `WeakSet` 的条目不是真正的引用,而是 [临时对象](https://dl.acm.org/doi/pdf/10.1145/263700.263733),对标记清除机制的增强。[Barros et al.](https://www.jucs.org/jucs_14_21/eliminating_cycles_in_weak/jucs_14_21_3481_3497_barros.pdf) 对算法提供了一个很好的总结(第 4 页)。引用一段: +假设 `key` 存储为真实的引用,它将创建一个循环引用,让键和值都不适合垃圾回收,即使在 `key` 没有被引用时——因为假设 `key` 被垃圾回收了,这意味着在某个特定的时刻,`value.key` 将指向一个不存在的地址,而这是非法的。为了修复这个,`WeakMap` 和 `WeakSet` 的条目不是真正的引用,而是[临时对象](https://dl.acm.org/doi/pdf/10.1145/263700.263733)(对标记清除机制的增强)。[Barros 等人](https://www.jucs.org/jucs_14_21/eliminating_cycles_in_weak/jucs_14_21_3481_3497_barros.pdf)对算法提供了一个很好的总结(第 4 页)。引用一段: > 临时对象是 weak pairs 的改进,在 pairs 中,键和值都不分类为弱或强。键的连接性决定了值的连接性,但值的连接性不会影响键的连接性。[...]当垃圾回收提供临时对象的支持时,它会出现三个阶段而不是两个(标记和清除)。 From 8714118dcccc120237b9e6438e49c772f7a0b0b7 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:43:36 +0800 Subject: [PATCH 22/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index f3b60ce6dd1576..254b2b79ba646a 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -237,7 +237,7 @@ class MyWeakMap { ### WeakRefs 和 FinalizationRegistry -> **Note:** `WeakRef` 和 `FinalizationRegistry` 能直接内省进垃圾回收机制。[尽量避免使用](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#尽量避免使用)因为运行时语义几乎完全不受保证。 +> **备注:** `WeakRef` 和 `FinalizationRegistry` 能直接内省进垃圾回收机制。[尽量避免使用](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#尽量避免使用),因为运行时语义几乎完全不受保证。 所有用对象作为值的变量都是那个对象的引用。然而,这样的引用是*强引用*——它们的存在会阻止垃圾回收器将对象标记为适合回收。[`WeakRef`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) 是对象的*弱引用*,这让对象能被垃圾回收,同时在对象的声明周期期间仍保留了读取对象的内容的能力。 From 02a046a731fe4bd181e7de36833f1a9d2922891b Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:44:03 +0800 Subject: [PATCH 23/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 254b2b79ba646a..21d724046e6bfc 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -245,7 +245,7 @@ class MyWeakMap { ```js function cached(getter) { - // 一个 Map:从字符串 URL 到结果的 WeakRef + // 一个 Map:从字符串 URL 到 WeakRef 结果 const cache = new Map(); return async (key) => { if (cache.has(key)) { From 71b07bea0c6341ef323f4b519f8f03348f91efb5 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:44:26 +0800 Subject: [PATCH 24/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 21d724046e6bfc..ae5658029f60a8 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -263,7 +263,7 @@ function cached(getter) { const getImage = cached((url) => fetch(url).then((res) => res.blob())); ``` -[`FinalizationRegistry`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) 提供了一个更强的机制观察垃圾回收。它让你注册对象以及对象被垃圾回收时得到通知。例如,对于上面的缓存系统这个例子,即使在 blob 自身被垃圾回收时,引用 blob 的 `WeakRef` 对象不会被垃圾回收——随着时间的积累,`Map` 可能积聚大量的无用条目。在这里例子中,使用 `FinalizationRegistry` 能执行清除。 +[`FinalizationRegistry`](/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry) 提供了一个更强的机制观察垃圾回收。它让你注册对象以及对象被垃圾回收时得到通知。例如,对于上面的缓存系统这个例子,即使在 blob 自身被垃圾回收时,引用 blob 的 `WeakRef` 对象不会被垃圾回收——随着时间的积累,`Map` 可能积聚大量的无用条目。在这里的例子中,使用 `FinalizationRegistry` 能执行清除。 ```js function cached(getter) { From 66f9f4bc802020c8f3d71da1e35af0d2ab964ab6 Mon Sep 17 00:00:00 2001 From: familyboat <84062528+familyboat@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:44:51 +0800 Subject: [PATCH 25/27] Update files/zh-cn/web/javascript/memory_management/index.md Co-authored-by: Jason Ren <40999116+jasonren0403@users.noreply.github.com> --- files/zh-cn/web/javascript/memory_management/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index ae5658029f60a8..3d8cda769fa141 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -267,7 +267,7 @@ const getImage = cached((url) => fetch(url).then((res) => res.blob())); ```js function cached(getter) { - // 一个 Map:从字符串 URL 到结果的 WeakRef + // 一个 Map:从字符串 URL 到 WeakRef 结果 const cache = new Map(); // 每次值被垃圾回收之后,用缓存中的 key 作为参数调用回调,能移除缓存条目 const registry = new FinalizationRegistry((key) => { From 560a453081d7dfceb19b7e1aa0d54728ef6b6bc0 Mon Sep 17 00:00:00 2001 From: familyboat <2015301110129@whu.edu.cn> Date: Fri, 1 Nov 2024 17:56:53 +0800 Subject: [PATCH 26/27] =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- files/zh-cn/web/javascript/memory_management/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index 3d8cda769fa141..d320baff808359 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -143,7 +143,7 @@ function f() { const x = {}; const y = {}; x.a = y; // x 引用 y - y.a = x; // y 应用 x + y.a = x; // y 引用 x return "azerty"; } @@ -167,7 +167,7 @@ f(); ## 配置引擎的内存模型 -JavaScript 引擎典型地提供了暴露内存模型地标志。例如,Node.js 为配置和调试内存问题提供了暴露底层的 V8 机制的额外选项和工具。这个配置可能在浏览器中不能使用,Web 页面更不用说(通过 HTTP 标头,等等)。 +JavaScript 引擎典型地提供了暴露内存模型的标志。例如,Node.js 为配置和调试内存问题提供了暴露底层的 V8 机制的额外选项和工具。这个配置可能在浏览器中不能使用,Web 页面更不用说(通过 HTTP 标头,等等)。 最大可用堆内存可以通过使用标志来增加: ```bash From 107ed958da9d8ccb9f237b171cf856c840d44f5c Mon Sep 17 00:00:00 2001 From: Jason Ren <40999116+jasonren0403@users.noreply.github.com> Date: Sat, 2 Nov 2024 10:41:30 +0800 Subject: [PATCH 27/27] Update index.md --- files/zh-cn/web/javascript/memory_management/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/files/zh-cn/web/javascript/memory_management/index.md b/files/zh-cn/web/javascript/memory_management/index.md index d320baff808359..704fcbaf6306be 100644 --- a/files/zh-cn/web/javascript/memory_management/index.md +++ b/files/zh-cn/web/javascript/memory_management/index.md @@ -168,6 +168,7 @@ f(); ## 配置引擎的内存模型 JavaScript 引擎典型地提供了暴露内存模型的标志。例如,Node.js 为配置和调试内存问题提供了暴露底层的 V8 机制的额外选项和工具。这个配置可能在浏览器中不能使用,Web 页面更不用说(通过 HTTP 标头,等等)。 + 最大可用堆内存可以通过使用标志来增加: ```bash