Como obter o tamanho de um object JavaScript?

Eu quero saber o tamanho ocupado por um object JavaScript.

Tome a seguinte function:

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

Agora eu instancio o student :

 var stud = new Student(); 

para que eu possa fazer coisas como

 stud.firstName = "new Firstname"; alert(stud.firstName); stud.marks.maxMarks = 200; 

etc.

Agora, o object stud ocupará algum tamanho na memory. Tem alguns dados e mais objects.

Como eu descubro quanta memory o object stud ocupa? Algo como um sizeof() em JavaScript? Seria realmente incrível se eu pudesse encontrá-lo em uma única chamada de function como sizeof(stud) .

Eu tenho pesquisado na Internet há meses – não consegui encontrá-lo (perguntei em alguns fóruns – sem respostas).

    Eu refiz o código em minha resposta original . Eu removi a recursion e removi a sobrecarga presumida da existência.

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

    O Profiler de heap do Google Chrome permite que você inspecione o uso da memory de objects.

    Você precisa ser capaz de localizar o object no rastreamento que pode ser complicado. Se você fixar o object na janela global, é muito fácil encontrá-lo no modo de listview “Contenção”.

    Na captura de canvas anexada, criei um object chamado “testObj” na janela. Eu, então, localizei o profiler (depois de fazer uma gravação) e ele mostra o tamanho total do object e tudo o que está nele em “tamanho retido”.

    Mais detalhes sobre os colapsos de memory .

    Perfilador de cromo

    Na imagem acima, o object mostra um tamanho retido de 60. Eu acredito que a unidade é bytes aqui.

    Acabei de escrever isso para resolver um problema semelhante (ish). Ele não faz exatamente o que você está procurando, isto é, não leva em conta como o interpretador armazena o object.

    Mas, se você estiver usando o V8, ele deve lhe dar uma boa aproximação, já que o incrível protótipo e as classs ocultas lambem a maior parte da sobrecarga.

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

    Às vezes eu uso isso para sinalizar objects realmente grandes que podem estar indo para o cliente do servidor. Não representa a pegada na memory. Apenas você recebe aproximadamente o que custaria para enviá-lo ou armazená-lo.

    Observe também, é lento, dev apenas. Mas para obter uma resposta de jogo com uma linha de código, ela tem sido útil para mim.

     roughObjSize = JSON.stringify(bigObject).length; 

    Existe um módulo NPM para obter o npm install object-sizeof , você pode instalá-lo com o 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)); 

    Um pouco atrasado para a festa, mas aqui está uma solução um pouco mais compacta para o problema:

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

    Este é um método hacky, mas eu tentei duas vezes com números diferentes e parece ser consistente.

    O que você pode fazer é tentar alocar um grande número de objects, como um ou dois milhões de objects do tipo que você deseja. Coloque os objects em uma matriz para evitar que o coletor de lixo os libere (note que isso irá adicionar uma pequena sobrecarga de memory por causa da matriz, mas eu espero que isso não importe e, além disso, se você se preocupará com objects que estão na memory , você os armazena em algum lugar). Adicione um alerta antes e depois da alocação e, em cada alerta, verifique quanta memory o processo do Firefox está tomando. Antes de abrir a página com o teste, verifique se você possui uma nova instância do Firefox. Abra a página e observe o uso da memory depois que o alerta “antes” for exibido. Feche o alerta, espere a memory ser alocada. Subtraia a nova memory da mais antiga e divida-a pela quantidade de alocações. Exemplo:

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

    Eu tentei isso no meu computador e o processo tinha 48352K de memory quando o alerta "antes" foi mostrado. Após a alocação, o Firefox tinha 440236K de memory. Para 2 milhões de alocações, isto é aproximadamente 200 bytes para cada object.

    Eu tentei novamente com 1 milhão de alocações e o resultado foi similar: 196 bytes por object (suponho que os dados extras em 2 mill foram usados ​​para Array).

    Então, aqui está um método hacky que pode ajudá-lo. O JavaScript não fornece um método "sizeof" por um motivo: cada implementação JavaScript é diferente. No Google Chrome, por exemplo, a mesma página usa cerca de 66 bytes para cada object (a julgar pelo menos pelo gerenciador de tarefas).

    Desculpe eu não pude comentar, então eu apenas continuo o trabalho do tomwrong. Esta versão melhorada não contará o object mais de uma vez, portanto, não há loop infinito. Além disso, eu acho que a chave de um object também deve ser contada, aproximadamente.

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

    Eu quero saber se meus esforços de redução de memory realmente ajudam na redução de memory

    Seguindo este comentário, aqui está o que você deve fazer: Tente produzir um problema de memory – Grave código que cria todos esses objects e aumente gramatalmente o limite superior até encontrar um problema (travamento do navegador, congelamento do navegador ou erro de memory). O ideal é que você repita essa experiência com diferentes navegadores e diferentes sistemas operacionais.

    Agora existem duas opções: opção 1 – você não conseguiu produzir o problema de memory. Portanto, você está se preocupando por nada. Você não tem um problema de memory e seu programa está bem.

    opção 2- você conseguiu um problema de memory. Agora, pergunte-se se o limite em que o problema ocorreu é razoável (em outras palavras: é provável que essa quantidade de objects seja criada no uso normal de seu código). Se a resposta for “Não”, então você está bem. Caso contrário, você já sabe quantos objects seu código pode criar. Retrabalhe o algoritmo de forma que ele não viole esse limite.

    Esta biblioteca Javascript sizeof.js faz a mesma coisa. Incluí-lo assim

      

    A function sizeof usa um object como parâmetro e retorna seu tamanho aproximado em bytes. Por exemplo:

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

    A function sizeof pode manipular objects que contêm várias referências a outros objects e referências recursivas.

    Originalmente publicado aqui .

    Tendo o mesmo problema. Eu procurei no Google e quero compartilhar com a comunidade stackoverflow esta solução.

    Importante :

    Eu usei a function compartilhada por Yan Qing no github https://gist.github.com/zensh/4975495

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

    Se sua principal preocupação é o uso de memory da sua extensão do Firefox, sugiro verificar com os desenvolvedores do Mozilla.

    A Mozilla fornece em seu wiki uma lista de ferramentas para analisar vazamentos de memory .

    As ferramentas de desenvolvedor do Chrome têm essa funcionalidade. Achei este artigo muito útil e faço exatamente o que você deseja: https://developers.google.com/chrome-developer-tools/docs/heap-profiling

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

    Muito obrigado a todos que estiveram trabalhando em código para isso!

    Eu só queria acrescentar que estive procurando exatamente a mesma coisa, mas no meu caso é para gerenciar um cache de objects processados ​​para evitar a necessidade de analisar novamente e processar objects de chamadas ajax que podem ou não ter sido armazenadas em cache pelo navegador. Isso é especialmente útil para objects que exigem muito processamento, geralmente qualquer coisa que não esteja no formato JSON, mas pode ser muito caro manter essas coisas armazenadas em cache em um projeto grande ou em um aplicativo / extensão que fica em execução por um longo período. Tempo.

    De qualquer forma, eu uso para algo como:

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

    É um exemplo simplista e pode ter alguns erros, mas dá a ideia, já que você pode usá-lo para segurar objects estáticos (o conteúdo não muda) com algum grau de inteligência. Isso pode reduzir significativamente os requisitos de processamento caros que o object teve que ser produzido em primeiro lugar.

    Eu uso a guia Cronograma das ferramentas de desenvolvimento do Chrome, instanciar quantidades cada vez maiores de objects e obter boas estimativas como essa. Você pode usar html como este abaixo, como clichê, e modificá-lo para melhor simular as características de seus objects (número e tipos de propriedades, etc …). Você pode querer clicar no ícone de lixeira na parte inferior da aba de ferramentas de desenvolvimento, antes e depois de uma execução.

        Quantifier:     

    A instanciação de 2 milhões de objects de apenas uma propriedade cada (como neste código acima) leva a um cálculo aproximado de 50 bytes por object, no meu Chromium, agora mesmo. Alterar o código para criar uma string aleatória por object adiciona cerca de 30 bytes por object, etc. Espero que isso ajude.

    Se você precisar programaticamente verificar por aprox. tamanho dos objects, você também pode verificar esta biblioteca http://code.stephenmorley.org/javascript/finding-the-memory-usage-of-objects/ que eu pude usar para o tamanho dos objects.

    Caso contrário, sugiro usar o Profiler Heap do Chrome / Firefox.

    Eu acredito que você esqueceu de include ‘array’.

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

    Eu sei que isso não é absolutamente o jeito certo de fazê-lo, ainda que tenha me ajudado algumas vezes no passado a obter o tamanho aproximado do arquivo de object:

    Escreva seu object / resposta no console ou em uma nova guia, copie os resultados para um novo arquivo do bloco de notas, salve-o e verifique o tamanho do arquivo. O próprio arquivo do bloco de notas tem apenas alguns bytes, portanto, você obterá um tamanho de arquivo de object bastante preciso.