Как получить размер объекта JavaScript?

Я хочу знать размер, занимаемый объектом 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? Что-то вроде sizeof() в JavaScript? Было бы действительно здорово, если бы я смог найти это в одном вызове функции, например sizeof(stud).

Я искал интернет в течение нескольких месяцев - не мог найти его (спросил на нескольких форумах - нет ответов).

Ответ 1

Я переустановил код в своем исходном ответе. Я удалил рекурсию и удалил предполагаемые накладные расходы.

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

Ответ 2

Google Chrome Heap Profiler позволяет вам проверять использование памяти объектов.

Вам нужно найти объект в трассировке, которая может быть сложной. Если вы привяжете объект к глобальному окну, его легко найти в режиме листинга "Containment".

В прикрепленном скриншоте я создал объект, называемый "testObj" в окне. Затем я находился в профилировщике (после записи), и он показывает полный размер объекта и все в нем под "сохраненным размером".

Подробнее о поломках памяти.

Chrome profiler

В приведенном выше скриншоте объект показывает сохраненный размер 60. Я считаю, что единица здесь байтов.

Ответ 3

Я просто написал это, чтобы решить аналогичную проблему (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 );
}

Ответ 4

Иногда я использую это для обозначения действительно больших объектов, которые могут быть отправлены клиенту с сервера. Он не отражает объем памяти. Это просто дает вам примерно то, что стоило бы отправить его, или сохранить его.

Также обратите внимание, что он медленный, только dev. Но для того, чтобы получить ответ на блайнд с одной строкой кода, это было полезно для меня.

roughObjSize = JSON.stringify(bigObject).length;

Ответ 5

Существует модуль 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));

Ответ 6

Немного поздно на вечеринку, но здесь немного более компактное решение проблемы:

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

Ответ 7

Это хакерский метод, но я дважды пробовал его с разными номерами, и он кажется последовательным.

Что вы можете сделать, это попытаться выделить огромное количество объектов, например, один или два миллиона объектов, которые вы хотите. Поместите объекты в массив, чтобы сборщик мусора не выпустил их (обратите внимание, что это добавит небольшие издержки памяти из-за массива, но я надеюсь, что это не имеет значения, и, кроме того, если вы будете беспокоиться об объектах, находящихся в памяти, вы их где-то храните). Добавьте предупреждение до и после выделения и в каждом предупреждении проверьте, сколько памяти занимает процесс 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 памяти, когда было показано предупреждение "before". После выделения Firefox имел 440236 КБ памяти. Для 2миллионных распределений это составляет около 200 байт для каждого объекта.

Я попробовал это снова с 1 миллионом распределений, и результат был похож: 196 байт на объект (я полагаю, дополнительные данные в 2mill были использованы для Array).

Итак, вот хакерский метод, который может вам помочь. JavaScript не предоставляет метод "sizeof" по одной причине: каждая реализация JavaScript отличается. В Google Chrome, например, одна и та же страница использует около 66 байт для каждого объекта (как минимум, из диспетчера задач).

Ответ 8

Извините, я не могу комментировать, поэтому я просто продолжаю работу из 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);

Ответ 9

Я хочу знать, действительно ли мои усилия по уменьшению памяти помогают уменьшить память.

Следуя за этим комментарием, вот что вам следует делать: Попытайтесь создать проблему с памятью. Напишите код, который создает все эти объекты, и градиентно увеличит верхний предел до тех пор, пока вы не столкнетесь с проблемой (сбой браузера, замораживание браузера или ошибка Out-Of-memory). В идеале вам следует повторить этот эксперимент с разными браузерами и другой операционной системой.

Теперь есть два варианта: вариант 1 - Вам не удалось создать проблему с памятью. Следовательно, вы беспокоитесь ни о чем. У вас нет проблемы с памятью, и ваша программа в порядке.

вариант 2, у вас возникла проблема с памятью. Теперь спросите себя, является ли ограничение, при котором возникла проблема, разумным (другими словами: возможно ли, что это количество объектов будет создано при нормальном использовании вашего кода). Если ответ "Нет", тогда все в порядке. В противном случае вы теперь знаете, сколько объектов может создать ваш код. Исправьте алгоритм таким образом, чтобы он не нарушал этот предел.

Ответ 10

Эта библиотека 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 может обрабатывать объекты, которые содержат несколько ссылок на другие объекты и рекурсивные ссылки.

Первоначально опубликовано здесь.

Ответ 11

С той же проблемой. Я искал в Google, и я хочу поделиться с сообществом stackoverflow этим решением.

Важно:

Я использовал функцию, разделяемую Ян Цин на 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);

Ответ 14

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

Ответ 15

Большое спасибо всем, кто работает над кодом для этого!

Я просто хотел добавить, что я искал точно то же самое, но в моем случае это для управления кешем обработанных объектов, чтобы избежать необходимости повторного анализа и обработки объектов из вызовов 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
    },
};

Это упрощенный пример и может иметь некоторые ошибки, но он дает идею, поскольку вы можете использовать ее для хранения на статических объектах (содержимое не изменится) с некоторой степенью интеллекта. Это может значительно сократить любые дорогостоящие требования к обработке, которые должен был быть произведен в первую очередь.

Ответ 16

Я использую инструменты Chrome dev вкладка Timeline, создавайте все большее количество объектов и получайте хорошие оценки. Вы можете использовать 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>

Создавая 2 миллиона объектов только одного свойства каждый (как в этом коде выше), приводит к грубому вычислению 50 байтов на объект, на моем Chromium, прямо сейчас. Изменение кода для создания случайной строки на объект добавляет около 30 байт на объект и т.д. Надеюсь, это поможет.

Ответ 17

Если вам нужно программно проверить aprox. размер объектов, вы также можете проверить эту библиотеку http://code.stephenmorley.org/javascript/finding-the-memory-usage-of-objects/, которую я смог использовать для размера объектов.

В противном случае я предлагаю использовать Chrome/Firefox Heap Profiler.

Ответ 18

Я полагаю, вы забыли включить "массив".

  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

Я знаю, что это абсолютно не правильный способ сделать это, но это помогло мне несколько раз в прошлом, чтобы получить приблизительный размер объектного файла:

Напишите свой объект/ответ на консоль или новую вкладку, скопируйте результаты в новый файл блокнота, сохраните его и проверьте размер файла. Сам файл блокнота - всего несколько байтов, поэтому вы получите довольно точный размер объектного файла.