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

取以下函数:

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

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

现在我实例化这个学生:

var stud = new Student();

这样我就可以做

stud.firstName = "new Firstname";

alert(stud.firstName);

stud.marks.maxMarks = 200;

etc.

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

我如何找出有多少内存stud对象占用?类似于JavaScript中的sizeof() ?如果我能在一个函数调用中找到它,比如sizeof(stud),那就太棒了。

我已经在网上搜索了几个月了——没有找到它(在几个论坛上被问到——没有回复)。


当前回答

接受的答案不适用于Map, Set, WeakMap和其他可迭代对象。(在其他回答中提到的包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一起工作。

其他回答

对不起,我不能评论,所以我只能从明天开始继续工作。 此增强版本不会对对象进行多次计数,因此不会出现无限循环。 另外,我认为一个物体的键也应该粗略地计算。

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

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

原文发表于此。

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

What you can do is to try and allocate a huge number of objects, like one or two million objects of the kind you want. Put the objects in an array to prevent the garbage collector from releasing them (note that this will add a slight memory overhead because of the array, but i hope this shouldn't matter and besides if you are going to worry about objects being in memory, you store them somewhere). Add an alert before and after the allocation and in each alert check how much memory the Firefox process is taking. Before you open the page with the test, make sure you have a fresh Firefox instance. Open the page, note the memory usage after the "before" alert is shown. Close the alert, wait for the memory to be allocated. Subtract the new memory from the older and divide it by the amount of allocations. Example:

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');

我在我的计算机上尝试了这个方法,当“before”警告显示时,该进程有48352K的内存。分配之后,Firefox拥有440236K的内存。对于200万个分配,每个对象大约有200个字节。

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

所以,这里有一个可能对你有帮助的简单方法。JavaScript没有提供sizeof方法是有原因的:每个JavaScript实现都是不同的。以谷歌Chrome为例,相同的页面为每个对象使用大约66字节(至少从任务管理器判断)。

谷歌Chrome堆分析器允许您检查对象内存使用。

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

在附件的截图中,我在窗口上创建了一个名为“testObj”的对象。然后我定位在分析器(在做了一个记录后),它显示了对象的完整大小和它在“保留大小”下的所有内容。

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

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

在@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));