JS数组内存分配机制与push/unshift性能差异解析

作者:青柠时间:2026-10-24 23:14:25浏览:509

本文深入分析JavaScript数组在内存中的存储机制,探讨连续内存与非连续内存对操作效率的影响。通过对比push和unshift方法的底层实现,以及相同类型与混合类型数组的耗时测试,揭示数组元素移动和内存分配对性能的关键作用。

JS数组

JavaScript数组的物理内存布局与其他多数编程语言类似,通常分配在连续的内存空间中。这种连续存储结构意味着数组元素的移动次数越少,整体操作效率越高。通常情况下,数组会被分配在一块连续的内存区域中,具体示意如下。

JS数组

读者可能会疑惑,为何要特别强调内存边界?这是因为在定义数组时,系统通常会预设其长度。当我们需要向数组中添加新元素时,实际上是在修改这个预设长度,这涉及到内存空间的重新分配或扩展。

效率比较

JavaScript提供了多种便捷的API用于向数组添加元素,例如push和unshift方法。

  • push()方法用于在数组末尾添加元素。由于是在尾部操作,无需移动其他现有元素,系统仅需将this.length属性加1即可完成操作,效率较高。

  • unshift()方法用于在数组头部添加元素。虽然表面上看只是在头部增加了一个元素,但在底层实现中,为了保持内存的连续性,原有所有元素都必须向后移动一位(从尾部到头部顺序调整)。这种大量的元素移动操作凸显了其性能较差的特点,具体过程如下图所示。

JS数组

举个栗子🌰

为了直观比较两者的耗时差异,我们编写测试代码。结果显示,unshift操作耗时约0.24毫秒,而push操作耗时约0.8毫秒(注:原文数据可能存在特定测试环境差异,此处保留原文数值)。需要注意的是,随着需要移动的元素数量增加,耗时呈指数级增长。

function _shift() {
    var arr = []
    console.time('_shift')
    for (let i = 0; i < 1000; i++) {
      arr.unshift(1)
    }
    console.timeEnd('_shift')
  }
  _shift()
function _push() {
    var arr = []
    console.time('_push')
    for (let i = 0; i < 1000; i++) {
      arr.push(1)
    }
    console.timeEnd('_push')
  }
  _push()

JS数组

非连续内存问题

此外,JavaScript数组允许在同一数组中存储不同类型的数据。这导致内存分配是否连续取决于数组成员的类型:当所有成员类型相同时,系统倾向于分配连续内存;而当数组中包含对象、字符串等不同类型时,系统可能分配非连续内存,多个非连续内存块通过链表形式连接。当存储数据量达到庞大级别时,这种非连续结构会导致效率显著降低。下面针对数组成员类型相同与不同的情况进行耗时对比,为凸显效果,测试次数提升至10的7次幂。

  function _diff() {
    var arr = new Array(10000000)
    arr.push({ name: "cxy" })
    console.time('_diff')
    for (let i = 0; i < 10000000; i++) {
      arr[i] = i
    }
    console.timeEnd('_diff')
  }
  _diff()
  function _same() {
    var arr = new Array(10000000)
    console.time('_same')
    for (let i = 0; i < 10000000; i++) {
      arr[i] = i
    }
    console.timeEnd('_same')
  }
  _same()

JS数组

测试结果表明,非连续内存数组的操作耗时是连续内存数组的数倍,差距明显。

总结

本文介绍了JavaScript数组在内存中的效率问题,更多相关内容可搜索本站往期文章或浏览后续文章,希望大家支持本站!

作者最新文章