如何获得JavaScript对象的大小?

269 javascript memory object sizeof

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

采取以下功能:

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

function Student(){
  this.firstName = "firstName";
  this.lastName = "lastName";
  this.marks = new Marks();
}
Run Code Online (Sandbox Code Playgroud)

现在我实例化student:

var stud = new Student();
Run Code Online (Sandbox Code Playgroud)

所以我可以做类似的事情

stud.firstName = "new Firstname";

alert(stud.firstName);

stud.marks.maxMarks = 200;
Run Code Online (Sandbox Code Playgroud)

等等

现在,该stud对象将在内存中占用一些大小.它有一些数据和更多的对象.

如何找出stud对象占用的内存量?像sizeof()JavaScript中的东西?如果我能在单个函数调用中找到它,那将是非常棒的sizeof(stud).

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

tho*_*ter 162

我在原始答案中重新考虑了代码.我删除了递归并删除了假定的存在开销.

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 您可能还想要考虑对象键 (30认同)
  • 任何人为了虚假/真实的目的而在这里寻找最小的类型,它似乎是未定义/ null. (7认同)
  • 是的.JavaScript中的字符根据ECMA-262第3版规范存储 - http://bclary.com/2004/11/07/#a-4.3.16 (7认同)
  • 此函数不计算隐藏在闭包中的引用.例如`var a = {n:1}; var b = {a:function(){return a}}; roughSizeOfObject(b)` - 这里`b`持有对`a`的引用,但`roughSizeOfObject()`返回`0`. (4认同)
  • ““” .length`在Javascript中为4,但是您确定它是8个字节,因为您的代码返回了它? (2认同)
  • 感谢Roman指出这一点.但是我不认为包含函数的结果会有意义,但以某种方式计算函数的大小可能会有用.我会调查一下.我也一直在考虑添加一个选项,其中包括'key'名称的大小. (2认同)
  • 祝贺您的努力,但是我只测试了这个`roughSizeOfObject(document.createElement('div'));`,我得到了`999694`,将近1MB。如果一个div的内存为1MB,那么我想知道该页面将需要`:D`多少内存。撇开笑话,它也为window和document返回相同的值,因此一定有问题。干杯! (2认同)
  • “您的对象大致是:'+(JSON.stringify(obj).length * 4/1024/1024)+'mb'+'一个utf8字形最多可以包含4个字节,这个数字通常是相当准确的。 (2认同)
  • 我认为这只是计算值,而不是对象键或其他对象元数据: ``` roughSizeOfObject(this._index) 29212 roughSizeOfObject(_.keys(this._index)) 144104 roughSizeOfObject(_.values(this._index)) 29212 ```` (2认同)
  • 太糟糕了,JS 中没有 `sizeOf()` 函数。我想这是因为它在很大程度上取决于客户端系统。但是为了优化代码,能够知道精确的大小是很酷的,它可以节省时间。(js 程序员通常不关心内存,但是当你在非常有限的嵌入式系统中工作时,你需要关心它)。 (2认同)

小智 105

Google Chrome Heap Profiler允许您检查对象内存使用情况.

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

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

关于内存故障的更多细节.

Chrome分析器

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

  • 这个答案解决了我的问题:https://developers.google.com/chrome-developer-tools/docs/heap-profiling.快速提示:快速获取堆快照,运行您怀疑泄漏的任务,使用新的快速堆快照并选择底部的"比较"视图.很明显,在两个快照之间创建了哪些对象. (11认同)
  • 您也可以从 node 使用 Google Chrome Heap Profiler。如果您有 node v8 或更高版本,请使用 `node --inspect` 启动它,然后在 Chrome 中的 URL 栏中输入 `about:inspect` 并寻找打开节点检查器。在节点 CLI 中创建您的对象,然后拍摄堆快照。 (2认同)

tho*_*ter 71

我刚写了这个来解决一个类似的(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 );
}
Run Code Online (Sandbox Code Playgroud)

  • 我需要注意的是PHP(gulp) - 我很久以前就不再爱她了,但是她付了账单.无论如何,感谢汤姆,反馈意见比声誉点更好. (4认同)

zst*_*tew 49

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

还要注意,它很慢,只有dev.但是为了获得一行代码的答案,这对我来说很有用.

roughObjSize = JSON.stringify(bigObject).length;
Run Code Online (Sandbox Code Playgroud)

  • 不能使用圆形结构`VM1409:1未捕获TypeError:将循环结构转换为JSON` :(虽然仍然有用但 (5认同)
  • 从我的测试来看,这个方法比object-sizeof case快得多,因为它没有来自lodash的慢_.isObject()调用.此外,对于粗略估计,返回的尺寸非常可比.要点https://gist.github.com/owenallenaz/ff77fc98081708146495. (2认同)
  • 太糟糕了[当对象太大时会分解](https://github.com/nodejs/node-v0.x-archive/issues/14170)。:( (2认同)

And*_*nak 38

有一个NPM模块可以获得对象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));
Run Code Online (Sandbox Code Playgroud)

  • 这似乎不太有用。它提供了一些类似于 C“sizeof”语义的理论数字,但不是实际使用的内存量。例如,对象本身会消耗空间(因此“sizeof(new Date())”应该>0),并且 JS 引擎通过删除重复字符串并在可能的情况下将它们存储在单字节编码中来节省内存。 (2认同)

Dan*_*Dan 37

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

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);
Run Code Online (Sandbox Code Playgroud)

  • 这是KB大小吗?或位? (2认同)
  • @ vincent-thorpe以字节为单位。 (2认同)
  • 漂亮的脚本,但是需要修改循环引用。 (2认同)
  • 我刚刚在一个节点进程中的大量数据上测试了你的算法,它报告了 13GB,但节点消耗了 22GB,知道差异来自哪里吗?记忆中没有更多的东西。 (2认同)
  • @JosuGoñi,他们不计算对象本身需要多少,仅计算其值。所有对象占用的空间不只是它们的值,否则`typeof ...`将不起作用。 (2认同)

Bad*_*tor 18

这是一个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');
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 每个C和C++实现也不同.;)C或C++中数据类型的大小是特定于实现的.我认为没有理由JavaScript不能支持这样的运算符,尽管它不会起到与C或C++相同的目的或意义(它们是低级语言并测量固定的实际大小 - 编译时大小数据类型,而不是运行时动态JavaScript对象的可变大小). (4认同)

Lia*_*eng 11

对不起,我无法评论,所以我只是继续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);
Run Code Online (Sandbox Code Playgroud)


Ala*_*ALI 9

有同样的问题.我在谷歌搜索,我想与stackoverflow社区分享这个解决方案.

重要:

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

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);
Run Code Online (Sandbox Code Playgroud)

你怎么看待这件事?

  • 这错过了功能.如果我添加一个函数,该对象不会显示任何更大的 (3认同)

Ita*_*man 7

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

继续这个评论,这是你应该做的:尝试产生内存问题 - 编写创建所有这些对象的代码并粗略地增加上限,直到遇到问题(浏览器崩溃,浏览器冻结或Out-Of-记忆错误).理想情况下,您应该使用不同的浏览器和不同的操作系统重复此实验

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

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


Vin*_*ert 5

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

Mozilla在其Wiki上提供了用于分析内存泄漏的工具列表


小智 5

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


Jay*_*ram 5

这个Javascript库sizeof.js做同样的事情。包括这样

<script type="text/javascript" src="sizeof.js"></script>
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

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

最初在这里发表