javascript - 为什么我的 Node.js 内存使用基准看起来是错误的?

标签 javascript node.js v8

我想测试 Node.js 中对象的内存使用情况。我的方法很简单:我首先使用 process.memoryUsage().heapUsed/1024/1024 来获取基线内存。我有一个大小数组,即对象中的条目数 const WIDTHS = [100, 500, 1000, 5000, 10000] 我计划循环遍历它并创建该大小的对象将当前内存使用情况与基线内存进行比较。

function memoryUsed() {
    const mbUsed = process.memoryUsage().heapUsed / 1024 / 1024 
    return mbUsed
}


function createObject(size) {
  const obj = {};
  for (let i = 0; i < size; i++) {
    obj[Math.random()] = i;
  }

  return obj;
}

const SIZES = [100, 500, 1000, 5000, 10000, 50000, 100000, 500000, 1000000]

const memoryUsage = {}

function fn() {
  SIZES.forEach(size => {
  const before = memoryUsed()
  const obj = createObject(size)
  const after = memoryUsed()
  const diff = after - before
  memoryUsage[size] = diff
})
}

fn()

但结果看起来不正确:

{
  '100': 0.58087158203125,
  '500': 0.0586700439453125,
  '1000': 0.15680694580078125,
  '5000': 0.7640304565429688,
  '10000': 0.30365753173828125,
  '50000': 7.4157257080078125,
  '100000': 0.8076553344726562,
}

这没有意义。另外,由于记录内存使用情况的对象 memoryUsage 本身会随着其增长而占用更多内存,因此我认为它会增加一些开销。

有哪些更强大、更正确的方法来对 Node.js 中的内存使用情况进行基准测试?

最佳答案

关键是缺少对垃圾收集器在“随机”时间启动的控制。要将使用的内存归因于执行的特定操作,您需要在进行测量之前手动触发完整 GC 运行。具体来说,修改 memoryUsed 使其显示为:

function memoryUsed() {
  gc();
  const mbUsed = process.memoryUsage().heapUsed / 1024 / 1024;
  return mbUsed;
}

并使用 --expose-gc 在 Node 中运行测试。然后你会得到合理的数字:

{
  '100': 0.20072174072265625,
  '500': 0.0426025390625,
  '1000': 0.08499908447265625,
  '5000': 0.37823486328125,
  '10000': 0.7519683837890625,
  '50000': 4.9071807861328125,
  '100000': 9.80963134765625,
  '500000': 43.04571533203125,
  '1000000': 86.08901977539062
}

第一个结果(100)显然太高了;不知道为什么(如果我最后重复 100 的测试,其结果与其他结果一致)。其他数字表明:如果属性数量增加 2 倍或 5 倍,内存消耗也会增加大约相同的 2 倍或 5 倍。


我的高级评论是,我不确定您在这里想要衡量什么。此场景中使用的大部分内存都花费在 "0.38459934255705686" 形式的字符串上,而您的描述似乎表明您对对象更感兴趣。
一个对象属性的边际成本取决于对象的状态:当多个对象共享一个形状/“隐藏类”时,对象中的每个属性只需要一个指针(在浏览器中为 4 个字节 [32 位平台,或指针压缩], Node 中 8 个字节[64 位,无指针压缩])。当对象处于字典模式时,每个附加属性平均需要大约 6 个指针(取决于字典的后备存储何时需要增长),因此需要 24 或 48 个字节,具体取决于指针大小。 (后者是此测试创建的场景。)
在这两种情况下,这只是持有该属性的对象的额外大小;属性的名称和值当然可能需要额外的内存。

关于javascript - 为什么我的 Node.js 内存使用基准看起来是错误的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72666770/

相关文章:

node.js - Google App Engine 标准不会压缩我的 Next.js/Express 应用程序

javascript - Chrome 没有运行 javascript 垃圾收集器

javascript - V8 中的 fatal error

javascript - 在 V8 的 Array.sort 中使用插入排序而不是希尔排序的理由是什么

javascript - 写入套接字非常快会导致连接缓冲区

干净地处理子对象的 JavaScript 框架?

javascript - 尝试读取文本文件 (.txt) 并在 onclick 按钮模式对话框中显示文本文件上的文本

Drupal 7 中的 Javascript 模块揭示并限定了 jQuery

javascript - 如何在 undefined object 上使用三元运算符

node.js - 引用错误: clientSecret is not defined in stripe