如何获取JavaScript对象的大小?

437

我想知道JavaScript对象所占用的大小。

请看以下函数:

function Marks(){
  this.maxMarks = 100;
}

function Student(){
  this.firstName = "firstName";
  this.lastName = "lastName";
  this.marks = new Marks();
}

现在我实例化student

var stud = new Student();

这样我就可以做类似以下的事情

stud.firstName = "new Firstname";

alert(stud.firstName);

stud.marks.maxMarks = 200;

现在,stud对象将占用一些内存空间。它有一些数据和更多的对象。

我该如何找出stud对象占用了多少内存?类似于JavaScript中的sizeof()吗?如果能够像sizeof(stud)这样进行单个函数调用来查找,那就太棒了。

我已经搜索了几个月的互联网 - 找不到答案(在一些论坛上发过帖子 - 没有回复)。


关于这个问题提出的答案怎么样:https://dev59.com/qm855IYBdhLWcg3wXC5- - csturtz
1
另一个内存近似函数在Github上(https://gist.github.com/zensh/4975495)。 - Rafael Emshoff
22个回答

7
这个 JavaScript 库 sizeof.js 能完成同样的任务。按照以下方式引入它:
<script type="text/javascript" src="sizeof.js"></script>

sizeof函数以一个对象作为参数,并返回其大致的字节大小。例如:

// define an object
var object =
    {
      'boolean' : true,
      'number'  : 1,
      'string'  : 'a',
      'array'   : [1, 2, 3]
    };

// determine the size of the object
var size = sizeof(object);

sizeof函数可以处理包含多个对其他对象的引用和递归引用的对象。

原始发布位置.


这比@liangliang的版本在我的使用情况下更慢,看起来也不够“精确”。 - cregox

5

5

3
接受的答案无法处理 MapSetWeakMap 和其他可迭代对象。(在其他答案中提到的object-sizeof包也有同样的问题。)
这是我的修复方法。
export function roughSizeOfObject(object) {
  const objectList = [];
  const stack = [object];
  const bytes = [0];
  while (stack.length) {
    const value = stack.pop();
    if (value == null) bytes[0] += 4;
    else if (typeof value === 'boolean') bytes[0] += 4;
    else if (typeof value === 'string') bytes[0] += value.length * 2;
    else if (typeof value === 'number') bytes[0] += 8;
    else if (typeof value === 'object' && objectList.indexOf(value) === -1) {
      objectList.push(value);
      if (typeof value.byteLength === 'number') bytes[0] += value.byteLength;
      else if (value[Symbol.iterator]) {
        // eslint-disable-next-line no-restricted-syntax
        for (const v of value) stack.push(v);
      } else {
        Object.keys(value).forEach(k => { 
           bytes[0] += k.length * 2; stack.push(value[k]);
        });
      }
    }
  }
  return bytes[0];
}

它还包括一些其他的小改进:计数键存储和与 ArrayBuffer 一起使用。

2
function sizeOf(parent_data, size)
{
    for (var prop in parent_data)
    {
        let value = parent_data[prop];

        if (typeof value === 'boolean')
        {
            size += 4;
        }
        else if (typeof value === 'string')
        {
            size += value.length * 2;
        }
        else if (typeof value === 'number')
        {
             size += 8;
        }
        else
        {      
            let oldSize = size;
            size += sizeOf(value, oldSize) - oldSize;
        }
    }

    return size;
}


function roughSizeOfObject(object)
{   
    let size = 0;
    for each (let prop in object)
    {    
        size += sizeOf(prop, 0);
    } // for..
    return size;
}

2
感谢所有为此工作的人!
我想补充一下,我一直在寻找完全相同的东西,但是对于我来说,它是用于管理已处理对象的缓存,以避免重新解析和处理ajax调用返回的对象,这些对象可能已经被浏览器缓存或者未被缓存。这对于需要大量处理的对象特别有用,通常是不在JSON格式中的任何对象,但是在一个大型项目或长时间运行的应用/扩展中,保持这些对象缓存会非常昂贵。
无论如何,我使用它来做类似于以下的事情:
var myCache = {
    cache: {},
    order: [],
    size: 0,
    maxSize: 2 * 1024 * 1024, // 2mb

    add: function(key, object) {
        // Otherwise add new object
        var size = this.getObjectSize(object);
        if (size > this.maxSize) return; // Can't store this object

        var total = this.size + size;

        // Check for existing entry, as replacing it will free up space
        if (typeof(this.cache[key]) !== 'undefined') {
            for (var i = 0; i < this.order.length; ++i) {
                var entry = this.order[i];
                if (entry.key === key) {
                    total -= entry.size;
                    this.order.splice(i, 1);
                    break;
                }
            }
        }

        while (total > this.maxSize) {
            var entry = this.order.shift();
            delete this.cache[entry.key];
            total -= entry.size;
        }

        this.cache[key] = object;
        this.order.push({ size: size, key: key });
        this.size = total;
    },

    get: function(key) {
        var value = this.cache[key];
        if (typeof(value) !== 'undefined') { // Return this key for longer
            for (var i = 0; i < this.order.length; ++i) {
                var entry = this.order[i];
                if (entry.key === key) {
                    this.order.splice(i, 1);
                    this.order.push(entry);
                    break;
                }
            }
        }
        return value;
    },

    getObjectSize: function(object) {
        // Code from above estimating functions
    },
};

这只是一个简单的例子,可能存在一些错误,但它能够表达一个想法,即您可以使用它来智能地保持静态对象(内容不会改变)。这可以显著减少对象在第一次生产时必须进行的任何昂贵的处理要求。


1
我使用Chrome开发者工具的时间轴选项卡,实例化越来越多的对象,并获得良好的估计结果。您可以使用以下类似的HTML作为样板,并修改它以更好地模拟您的对象特性(属性数量和类型等)。在运行之前和之后,您可能需要单击该开发工具选项卡底部的垃圾箱图标。
<html>
<script>
var size = 1000*100
window.onload = function() {
  document.getElementById("quantifier").value = size
}

function scaffold()
{
  console.log("processing Scaffold...");
  a = new Array
}

function start()
{
  size = document.getElementById("quantifier").value
  console.log("Starting... quantifier is " + size);
  console.log("starting test")
  for (i=0; i<size; i++){
    a[i]={"some" : "thing"}
  }
  console.log("done...")
}

function tearDown()
{
  console.log("processing teardown");
  a.length=0
}

</script>
<body>
    <span style="color:green;">Quantifier:</span>
    <input id="quantifier" style="color:green;" type="text"></input>
    <button onclick="scaffold()">Scaffold</button>
    <button onclick="start()">Start</button>
    <button onclick="tearDown()">Clean</button>
    <br/>
</body>
</html>

在这段代码中,每个对象只有一个属性,实例化了 200 万个对象,根据我的 Chromium 浏览器测试,每个对象大约占用 50 字节。如果修改代码,使每个对象都包含一个随机字符串,则每个对象增加大约 30 字节。


1

1
在@Dan已经提供的简洁解决方案基础上,这里提供了一个自包含函数版本。对于那些希望尽可能紧凑而不考虑上下文的人来说,变量名被缩减为单个字母。

const ns = {};
ns.sizeof = function(v) {
  let f = ns.sizeof, //this needs to match the name of the function itself, since arguments.callee.name is defunct
    o = {
      "undefined": () => 0,
      "boolean": () => 4,
      "number": () => 8,
      "string": i => 2 * i.length,
      "object": i => !i ? 0 : Object
        .keys(i)
        .reduce((t, k) => f(k) + f(i[k]) + t, 0)
    };
  return o[typeof v](v);
};

ns.undef;
ns.bool = true;
ns.num = 1;
ns.string = "Hello";
ns.obj = {
  first_name: 'John',
  last_name: 'Doe',
  born: new Date(1980, 1, 1),
  favorite_foods: ['Pizza', 'Salad', 'Indian', 'Sushi'],
  can_juggle: true
};

console.log(ns.sizeof(ns.undef));
console.log(ns.sizeof(ns.bool));
console.log(ns.sizeof(ns.num));
console.log(ns.sizeof(ns.string));
console.log(ns.sizeof(ns.obj));
console.log(ns.sizeof(ns.obj.favorite_foods));


1

我在使用 ArrayBuffer 时遇到了问题。查阅文档后,我发现 ArrayBuffer 有一个 byteLength 属性,可以告诉我需要的信息,因此代码如下:

function sizeOf(data)
{
    if (typeof(data) === 'object')
    {
        if (data instanceof ArrayBuffer)
        {
            return data.byteLength;
        }
        // other objects goes here
    }
    // non-object cases goes here
}

console.log(sizeOf(new ArrayBuffer(15))); // 15

参考资料:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接