如何获得JavaScript对象的大小?

时间:2009-08-08 07:58:17

标签: javascript memory object sizeof

我想知道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)这样的单一函数调用中找到它,那真是太棒了。

我已经在互联网上搜索了好几个月 - 找不到它(在几个论坛中询问 - 没有回复)。

20 个答案:

答案 0 :(得分:154)

我已经重新考虑了我original answer中的代码。我删除了递归并删除了假定的存在开销。

function roughSizeOfObject( object ) {

    var objectList = [];
    var stack = [ object ];
    var bytes = 0;

    while ( stack.length ) {
        var value = stack.pop();

        if ( typeof value === 'boolean' ) {
            bytes += 4;
        }
        else if ( typeof value === 'string' ) {
            bytes += value.length * 2;
        }
        else if ( typeof value === 'number' ) {
            bytes += 8;
        }
        else if
        (
            typeof value === 'object'
            && objectList.indexOf( value ) === -1
        )
        {
            objectList.push( value );

            for( var i in value ) {
                stack.push( value[ i ] );
            }
        }
    }
    return bytes;
}

答案 1 :(得分:96)

Google Chrome堆资源分析器允许您检查对象内存使用情况。

您需要能够在跟踪中找到可能很棘手的对象。如果您将对象固定到Window全局,则很容易从“Containment”列表模式中找到它。

在附带的屏幕截图中,我在窗口上创建了一个名为“testObj”的对象。然后我找到了探查器(在录制之后),它在“保留大小”下显示了对象的完整大小及其中的所有内容。

More details on the memory breakdowns

Chrome profiler

在上面的屏幕截图中,对象显示保留的大小为60.我相信这里的单位是字节。

答案 2 :(得分:66)

我刚写了这个来解决类似的(ish)问题。它并不完全符合您的要求,即它没有考虑解释器如何存储对象。

但是,如果你使用的是V8,它应该给你一个相当不错的近似值,因为真棒原型和隐藏类会舔掉大部分开销。

function roughSizeOfObject( object ) {

    var objectList = [];

    var recurse = function( value )
    {
        var bytes = 0;

        if ( typeof value === 'boolean' ) {
            bytes = 4;
        }
        else if ( typeof value === 'string' ) {
            bytes = value.length * 2;
        }
        else if ( typeof value === 'number' ) {
            bytes = 8;
        }
        else if
        (
            typeof value === 'object'
            && objectList.indexOf( value ) === -1
        )
        {
            objectList[ objectList.length ] = value;

            for( i in value ) {
                bytes+= 8; // an assumed existence overhead
                bytes+= recurse( value[i] )
            }
        }

        return bytes;
    }

    return recurse( object );
}

答案 3 :(得分:44)

有时我用它来标记可能从服务器进入客户端的真正大对象。它并不代表内存占用。它只是让您大致了解发送或存储它所需的成本。

另请注意,它只是缓慢的开发。但是,如果用一行代码得到一个棒球场答案,它对我有用。

roughObjSize = JSON.stringify(bigObject).length;

答案 4 :(得分:36)

有一个NPM module to get object sizeof,您可以使用npm install object-sizeof

进行安装
  var sizeof = require('object-sizeof');

  // 2B per character, 6 chars total => 12B
  console.log(sizeof({abc: 'def'}));

  // 8B for Number => 8B
  console.log(sizeof(12345));

  var param = { 
    'a': 1, 
    'b': 2, 
    'c': {
      'd': 4
    }
  };
  // 4 one two-bytes char strings and 3 eighth-bytes numbers => 32B
  console.log(sizeof(param));

答案 5 :(得分:29)

派对有点晚了,但这里有一个稍微紧凑的问题解决方案:

const typeSizes = {
  "undefined": () => 0,
  "boolean": () => 4,
  "number": () => 8,
  "string": item => 2 * item.length,
  "object": item => !item ? 0 : Object
    .keys(item)
    .reduce((total, key) => sizeOf(key) + sizeOf(item[key]) + total, 0)
};

const sizeOf = value => typeSizes[typeof value](value);

答案 6 :(得分:16)

这是一个hacky方法,但我尝试了两次不同的数字,它似乎是一致的。

您可以做的是尝试分配巨大的个对象,例如您想要的一两百万个对象。将对象放在一个数组中以防止垃圾收集器释放它们(请注意,这会因为数组而增加一点内存开销,但我希望这不重要,此外如果你要担心对象在内存中,你把它们存放在某处)。在分配之前和之后添加警报,并在每个警报中检查Firefox进程占用的内存量。在使用测试打开页面之前,请确保您有一个新的Firefox实例。打开页面,注意显示“之前”警报后的内存使用情况。关闭警报,等待分配内存。从较旧的内存中减去新内存并将其除以分配量。例如:

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

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

var manyObjects = new Array();
alert('before');
for (var i=0; i<2000000; i++)
    manyObjects[i] = new Student();
alert('after');

我在计算机上尝试了这个,当显示“之前”警报时,该过程有48352K的内存。配置完成后,Firefox拥有440236K的内存。对于2百万分配,每个对象大约200字节。

我再次尝试了100万次分配,结果相似:每个对象196个字节(假设2mill中的额外数据用于数组)。

所以,这是一个可能对你有帮助的hacky方法。由于某种原因,JavaScript不提供“sizeof”方法:每个JavaScript实现都是不同的。例如,在谷歌浏览器中,同一页面对每个对象使用大约66个字节(至少从任务管理器判断)。

答案 7 :(得分:10)

抱歉,我无法评论,所以我只是继续tomwrong的工作。 此增强版本不会多次计算对象,因此没有无限循环。 另外,我认为对象的关键也应该大致计算。

function roughSizeOfObject( value, level ) {
    if(level == undefined) level = 0;
    var bytes = 0;

    if ( typeof value === 'boolean' ) {
        bytes = 4;
    }
    else if ( typeof value === 'string' ) {
        bytes = value.length * 2;
    }
    else if ( typeof value === 'number' ) {
        bytes = 8;
    }
    else if ( typeof value === 'object' ) {
        if(value['__visited__']) return 0;
        value['__visited__'] = 1;
        for( i in value ) {
            bytes += i.length * 2;
            bytes+= 8; // an assumed existence overhead
            bytes+= roughSizeOfObject( value[i], 1 )
        }
    }

    if(level == 0){
        clear__visited__(value);
    }
    return bytes;
}

function clear__visited__(value){
    if(typeof value == 'object'){
        delete value['__visited__'];
        for(var i in value){
            clear__visited__(value[i]);
        }
    }
}

roughSizeOfObject(a);

答案 8 :(得分:6)

  

我想知道我的记忆减少努力是否真的有助于减少记忆

跟进此评论,这是您应该做的: 尝试产生内存问题 - 编写创建所有这些对象的代码并逐渐增加上限,直到遇到问题(浏览器崩溃,浏览器冻结或内存不足错误)。理想情况下,您应该使用不同的浏览器和不同的操作系统重复此实验。

现在有两种选择: 选项1 - 您没有成功产生内存问题。因此,你无所畏惧。你没有内存问题,你的程序也没问题。

选项2-你确实遇到了内存问题。现在问问自己问题发生的限制是否合理(换句话说:是否可能在正常使用代码时创建此数量的对象)。如果答案是“否”,那么你没事。否则,您现在知道代码可以创建多少个对象。重做算法,使其不会超出此限制。

答案 9 :(得分:5)

遇到同样的问题。我在Google上搜索过,我想与stackoverflow社区分享这个解决方案。

重要

  

我在github上使用了严清共享的功能   https://gist.github.com/zensh/4975495

&#13;
&#13;
function memorySizeOf(obj) {
    var bytes = 0;

    function sizeOf(obj) {
        if(obj !== null && obj !== undefined) {
            switch(typeof obj) {
            case 'number':
                bytes += 8;
                break;
            case 'string':
                bytes += obj.length * 2;
                break;
            case 'boolean':
                bytes += 4;
                break;
            case 'object':
                var objClass = Object.prototype.toString.call(obj).slice(8, -1);
                if(objClass === 'Object' || objClass === 'Array') {
                    for(var key in obj) {
                        if(!obj.hasOwnProperty(key)) continue;
                        sizeOf(obj[key]);
                    }
                } else bytes += obj.toString().length * 2;
                break;
            }
        }
        return bytes;
    };

    function formatByteSize(bytes) {
        if(bytes < 1024) return bytes + " bytes";
        else if(bytes < 1048576) return(bytes / 1024).toFixed(3) + " KiB";
        else if(bytes < 1073741824) return(bytes / 1048576).toFixed(3) + " MiB";
        else return(bytes / 1073741824).toFixed(3) + " GiB";
    };

    return formatByteSize(sizeOf(obj));
};


var sizeOfStudentObject = memorySizeOf({Student: {firstName: 'firstName', lastName: 'lastName', marks: 10}});
console.log(sizeOfStudentObject);
&#13;
&#13;
&#13;

你怎么看?

答案 10 :(得分:4)

如果您主要关心的是Firefox扩展程序的内存使用情况,我建议您与Mozilla开发人员联系。

Mozilla在其wiki上提供list of tools to analyze memory leaks

答案 11 :(得分:4)

Chrome开发者工具具有此功能。我发现这篇文章非常有用,并且完全符合您的要求: https://developers.google.com/chrome-developer-tools/docs/heap-profiling

答案 12 :(得分:4)

此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函数可以处理包含对其他对象和递归引用的多个引用的对象。

Originally published here

答案 13 :(得分: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;
}

答案 14 :(得分:1)

非常感谢为此准备代码的每个人!

我只是想补充一点,我一直在寻找完全相同的东西,但在我的情况下,它是用于管理已处理对象的缓存,以避免重新解析和处理来自ajax调用的对象,这可能会也可能不会已被浏览器缓存。这对于需要大量处理的对象尤其有用,通常是任何不是JSON格式的对象,但是将这些内容缓存在大型项目或长时间运行的app / extension中会非常昂贵时间。

无论如何,我用它来做类似的事情:

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
    },
};

这是一个简单的例子,可能会有一些错误,但它提供了这个想法,因为你可以用它来保持静态对象(内容不会改变),具有一定程度的智能。这可以显着减少必须首先生成对象的任何昂贵的处理要求。

答案 15 :(得分:1)

如果您需要以编程方式检查aprox。对象的大小你也可以检查我已经能够用于对象大小的这个库http://code.stephenmorley.org/javascript/finding-the-memory-usage-of-objects/

否则我建议使用Chrome / Firefox堆配置文件。

答案 16 :(得分:1)

我使用Chrome开发工具'Timeline tab,实例化越来越多的对象,并获得这样的好评估。您可以使用下面的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个字节等。 希望这会有所帮助。

答案 17 :(得分:0)

以@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: 'Brendan',
  last_name: 'Eich',
  born: new Date(1961, 6, 4),
  contributions: ['Netscape', 'JavaScript', 'Brave', 'BAT'],
  politically_safe: false
};

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.contributions));

答案 18 :(得分:-3)

我相信你忘了包含'阵列'。

  typeOf : function(value) {
        var s = typeof value;
        if (s === 'object')
        {
            if (value)
            {
                if (typeof value.length === 'number' && !(value.propertyIsEnumerable('length')) && typeof value.splice === 'function')
                {
                    s = 'array';
                }
            }
            else
            {
                s = 'null';
            }
        }
        return s;
    },

   estimateSizeOfObject: function(value, level)
    {
        if(undefined === level)
            level = 0;

        var bytes = 0;

        if ('boolean' === typeOf(value))
            bytes = 4;
        else if ('string' === typeOf(value))
            bytes = value.length * 2;
        else if ('number' === typeOf(value))
            bytes = 8;
        else if ('object' === typeOf(value) || 'array' === typeOf(value))
        {
            for(var i in value)
            {
                bytes += i.length * 2;
                bytes+= 8; // an assumed existence overhead
                bytes+= estimateSizeOfObject(value[i], 1)
            }
        }
        return bytes;
    },

   formatByteSize : function(bytes)
    {
        if (bytes < 1024)
            return bytes + " bytes";
        else
        {
            var floatNum = bytes/1024;
            return floatNum.toFixed(2) + " kb";
        }
    },

答案 19 :(得分:-6)

知道这绝对不是正确的方法,但过去曾帮助我几次获得大约目标文件大小:

将对象/响应写入控制台或新选项卡,将结果复制到新的记事本文件,保存并检查文件大小。记事本文件本身只有几个字节,因此您将获得相当准确的目标文件大小。