在 Chrome 中 JavaScript 数组到底占用了多少内存?

JavaScript数组内存占用解析
本文探究了JavaScript数组在Chrome浏览器中的内存占用情况,通过实验发现空数组和数字数组的实际内存占用与预期不符,并分析了背后的原因。此外,还介绍了如何使用Chrome内存分析器进行深入研究。

原文:How much memory do JavaScript arrays take up in Chrome?
译者:justjavac

因为我(原作者)的代码使用的很大的内存,所以我看了一下字符串、对象、数字和数组分别占用了多少内存。

结果如下:

array memory chart justjavac

我觉得这些数据最大的挑战是,空数组或者空列表占用的内存太小了。

因此我创建了大量空列表,而不是每次重新使用相同的空列表。

-  总大小 MB每一项的大小 Byte
Empty Fields7.638.00
Booleans9.279.72
Numbers9.279.72
Identical Strings9.279.72
Arrays39.7941.72
Empty Objects62.6865.72

我不完全理解这些结果。它们依赖于 JavaScript 引擎的内部结构。

空字段的大小是有道理的。每一项正好占用 8 个字节。(整个数组实际上占用了 8,000,048 个字节,因此有 48 个字节是数组本身的开销。)

但是,数字的数组却不符合我的期望。JavaScript 使用双精度(64 位)浮点数。64 位是 8 字节,但是每个数字平均占用了 9.7 字节。

同样,Chrome 将每个空数组的大小显示为 32 字节,每个空对象的大小为 56 字节。然而,整个数组的平均大小分别为 39.8 和 62.7。

我猜测之所以造成这个差异,一部分来自于 V8 存储数组项的元数据(例如类型信息),并且 Chrome 为数组提供的空间比实际最低要求的空间要多一些。另外,并不是所有的数组在 V8 内部都是相同的。2011 年的这篇博文(value representation in javascript implementations)也很不错。

(译注:以后有时间再写一篇关于 V8 数组内部存储原理的文章,by justjavac)

// Inheritance hierarchy:
// - Object
//   - Smi          (immediate small integer)
//   - HeapObject   (superclass for everything allocated in the heap)
//     - JSReceiver  (suitable for property access)
//       - JSObject
//         - JSArray
//         - JSArrayBuffer
//         - JSArrayBufferView
//           - JSTypedArray

如果要在 Chrome 中使用内存分析器(Profiler),可以使用此 CodePen 或从 Github 获取代码。

memory profiler - justjavac

It’s also interesting to see what the table looks like with only item in each array:

-数组总大小
Empty Field56
Boolean184
Number184
String216
Array216
Empty Object240

译文完。


补充一些相关知识点,关于 Chrome 内存分析器(Profiler)的使用。

当我们使用内存分析器时,要先创建一个纯净的环境,可以在新建标签页时选择隐身模式或者访客模式。再高级点的用法就是自己新建一个 Chrome 桌面快捷方式并配置相关的命令行参数。

如果你查看了之前的文章,文中提到“打开 Profiles 面板”时,你可能在你的 Chrome 中找不到这个面板,因为 Profiles 已经改名了,现在是 Memory 面板。

在 Memory 面板中,选择 Take Heap Snapshot,可以制作一个堆内存快照。Google 开发者中心有一篇非常不错的文章(有中文版),“如何记录堆快照”:https://developers.google.com...


欢迎关注我的公众号,关注前端文章:

justjavac微信公众号

<think> 我们已掌握关于Chrome DevTools检测内存泄漏的两则引用信息,用户明确要求了解检测并解决内存泄漏问题的方法。以下将结合引用内容和DevTools实际操作展开说明: ### 一、内存泄漏检测的核心工具(引用[1][2]关键工具) 1. **Heap Snapshot(堆快照)** - **原理**:捕获JS内存中所有对象的静态结构,通过对比快照分析对象增量。 - **操作流程**: 1. 打开DevTools → Memory面板 → 选择"Heap snapshot" → 点击"Take snapshot"生成基准快照(Snapshot 1)。 2. 执行疑似泄漏操作(如反复打开/关闭弹窗)。 3. 再次生成快照(Snapshot 2、Snapshot 3)。 4. 在快照列表中选择"Comparison"对比模式,观察`# Delta`列(正值表示新增对象)。 - **分析重点**: - 筛选`#Delta > 0`的对象,检查是否预期内应被回收的对象(如游离的DOM节点)。 - 右键点击对象 → "Reveal in Summary view" → 查看`Retainers`(引用链),定位未释放的根源[^2]。 2. **Allocation instrumentation on timeline(内存分配时间轴)** - **原理**:实时记录对象分配堆栈,定位频繁分配且未回收的内存。 - **操作流程**: 1. 选择"Allocation instrumentation on timeline" → 点击"Start"。 2. 执行用户操作(如滚动列表)。 3. 点击"Stop"生成报告。 - **分析重点**: - 查看蓝色竖条(表示未回收的对象),点击对应堆栈定位到代码文件和行号[^1]。 3. **Performance Monitor(性能监控器)** - **原理**:实时监测JS大小、DOM节点数等关键指标。 - **操作流程**: 1. DevTools → More tools → Performance Monitor。 2. 勾选"JS Heap Size"和"Nodes"。 - **分析重点**: - 若`JS Heap Size`或`Nodes`持续上升且不回落,可能存在泄漏[^1]。 --- ### 二、典型内存泄漏场景与解决方案 | 泄漏类型 | 检测线索 | 修复方法 | |-------------------|-----------------------------------|--------------------------------------------------------------------------| | **游离DOM引用** | `Detached` DOM节点在堆快照中残留 | 移除对DOM元素的变量引用(例:`document.getElementById('elem') = null`) | | **未清除监听器** | 事件监听器数量在时间轴上持续增加 | 使用`removeEventListener`或弱引用API(如`WeakRef`) | | **全局变量累积** | 全局对象(如`window.obj`)持续增大 | 避免全局存储,改用模块作用域或闭包 | | **定时器未清理** | `setInterval`回调函数未被回收 | 调用`clearInterval`/`clearTimeout` | > **案例演示**(游离DOM节点泄漏): > 1. 堆快照对比显示`Detached HTMLDivElement`数量增加 → 检查`Retainer`链发现被全局数组`window.cache`引用。 > 2. 解决方案:移除DOM元素时同步清理`cache`数组中的引用。 --- ### 三、自动化检测进阶 - **内存压力测试**: 使用DevTools → Performance面板 → 勾选"Memory" → 录制操作过程,观察JS Heap曲线是否阶梯上升。 - **强制垃圾回收**: 在Memory面板点击垃圾桶图标(🗑️),手动触发GC后对比快照,排除临时对象干扰[^2]。 --- ### 总结 通过Heap Snapshot对比、Allocation timeline定位和Performance Monitor监控,可精准识别内存泄漏。修复核心在于断开无效引用(尤其DOM和全局对象),并善用弱引用机制。建议结合快照对比与时间轴分析交叉验证[^1][^2]。 §§相关问题§§ 1. 如何区分内存泄漏与正常的内存占用? 2. Chrome DevTools中如何追踪闭包引起的内存泄漏? 3. 弱引用(WeakRef)在解决内存泄漏中的具体应用有哪些? </think> ### Chrome DevTools 检测并解决内存泄漏问题的方法 内存泄漏是 Web 应用性能问题的常见原因,表现为内存占用持续增长甚至导致页面崩溃。以下是使用 Chrome DevTools 的完整解决方案: #### 一、核心检测工具与流程(基于引用[1][2]) 1. **堆快照对比分析(Heap Snapshot)** - **操作步骤**: - 打开 DevTools → Memory 面板 → 选择 **Heap snapshot** - 初始状态点击 **Take Heap Snapshot**(基准快照 Snapshot 1) - 执行疑似泄漏操作(如页面交互/数据加载) - 生成第二次快照(Snapshot 2),重复操作后再生成 Snapshot 3 - 在快照列表选择 **Comparison** 模式,分析对象增量(Delta 列) - **关键指标**: - 重点关注 `Delta > 0` 且持续增长的对象类型(如 Detached DOM 节点) - 检查 `Retainers` 标签页,定位持有引用的代码链[^1][^2] 2. **内存分配时间轴(Allocation instrumentation)** - **操作步骤**: - 选择 **Allocation instrumentation on timeline** - 点击 **Start** → 执行用户操作 → **Stop** - 观察蓝色竖条(未回收内存)对应的堆栈 - **分析重点**: - 蓝色竖条高度表示未回收内存大小 - 点击竖条查看分配位置的源代码文件及行号[^1] 3. **性能监控器(Performance Monitor)** - **实时指标**: - 开启 **More Tools → Performance Monitor** - 监控 `JS Heap Size`(JavaScript内存) - 观察 `Nodes`(DOM 节点数)和 `Listeners`(事件监听器数) - **泄漏特征**: - 页面静止时指标持续阶梯式上升 - 手动垃圾回收(GC)后内存不回落[^1] #### 二、典型内存泄漏场景与修复方案 | 泄漏类型 | 检测特征 | 修复方案 | |-------------------|-----------------------------------|--------------------------------------------------------------------------| | **游离DOM节点** | `Detached HTMLDivElement` 增量 | 移除 JavaScript 中对 DOM 元素的引用 | | **未解绑监听器** | `Event listeners` 持续增加 | 使用 `removeEventListener()` 或弱引用(WeakRef) | | **闭包累积** | `Closure` 对象数量异常 | 避免在循环中创建闭包,及时释放外部变量 | | **定时器未清除** | `setInterval` 回调函数未被回收 | 使用 `clearInterval()`/`clearTimeout()` | | **全局变量堆积** | `Window` 对象体积增大 | 使用模块作用域代替全局变量,必要时手动置空 `obj = null` | #### 三、实战案例:检测弹窗组件的泄漏 1. **复现步骤**: - 记录初始堆快照 Snapshot 1 - 重复打开/关闭弹窗 10 次 - 记录 Snapshot 2 并选择 **Comparison** 模式 2. **分析结果**: ```plaintext Constructor # Delta Size Delta ------------------ ------- ---------- Detached HTMLDivElement +38 +120KB EventListener +76 +4KB ``` 3. **定位代码**: - 展开 `Detached HTMLDivElement` → 查看 `Retainer` 链 - 发现被全局数组 `window.cache` 引用 4. **修复方案**: ```javascript // 泄漏代码 window.cache.push(modalElement); // 修复后:组件卸载时清理引用 modal.onClose = () => { window.cache = window.cache.filter(el => el !== modalElement); modalElement.remove(); // 移除DOM }; ``` #### 四、高级技巧 1. **强制垃圾回收**: - 在 Memory 面板点击 ️ 图标手动触发 GC,验证内存是否回落 2. **内存压力测试**: - 使用 Performance 面板录制,勾选 **Memory** 选项,观察 JS Heap 曲线 3. **自动化检测**: ```javascript // 在控制台定期打印内存状态 setInterval(() => { console.log(performance.memory.usedJSHeapSize / 1024 / 1024 + 'MB'); }, 1000); ``` > **关键原则**:内存泄漏的本质是 **预期外的对象引用保持**,修复核心在于识别并切断无效引用链[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值