340

I want to know the size occupied by a JavaScript object.

Take the following function:

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

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

Now I instantiate the student:

var stud = new Student();

so that I can do stuff like

stud.firstName = "new Firstname";

alert(stud.firstName);

stud.marks.maxMarks = 200;

etc.

Now, the stud object will occupy some size in memory. It has some data and more objects.

How do I find out how much memory the stud object occupies? Something like a sizeof() in JavaScript? It would be really awesome if I could find it out in a single function call like sizeof(stud).

I’ve been searching the Internet for months—couldn’t find it (asked in a couple of forums—no replies).

Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61

20 Answers20

199

I have re-factored the code in my original answer. I have removed the recursion and removed the assumed existence overhead.

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;
}
Community
  • 1
  • 1
thomas-peter
  • 6,952
  • 6
  • 37
  • 56
  • 37
    you may want to think of the object keys as well – zupa Jan 24 '13 at 16:28
  • 8
    Anyone who landed here looking for the smallest type for the purposes of false/true, it seems to be undefined/null. – zupa Jan 24 '13 at 16:32
  • 3
    `"よんもじ".length` is 4 in Javascript, but are you sure it's 8 bytes, as your code returns it? – syockit Jul 17 '13 at 13:46
  • 8
    Yep. Characters in JavaScript are stored according to ECMA-262 3rd Edition Specification - http://bclary.com/2004/11/07/#a-4.3.16 – thomas-peter Jul 17 '13 at 14:16
  • This returns 0 for circular objects. Is that intended? – tjvr Mar 11 '14 at 22:30
  • If the object just contains a reference to itself, then yes. – thomas-peter Mar 17 '14 at 03:35
  • I found this very useful so I put it in a Gist: https://gist.github.com/pgpbpadilla/10344038 – pgpb.padilla Apr 10 '14 at 05:06
  • 4
    This function do not count references hidden in closures. For example `var a={n:1}; var b={a:function(){return a}}; roughSizeOfObject(b)` — here `b` holds reference to `a`, but `roughSizeOfObject()` returns `0`. – Roman Pominov May 10 '14 at 15:22
  • 2
    Thanks Roman for pointing this out. I don't think however think it would very meaningful to include the result of functions but it might be useful to somehow calculate the size of the function. I'll look into it. I've also been considering adding an option which will include the size of the 'key' name. – thomas-peter May 13 '14 at 12:32
  • 1
    Wouldnt it be more accurate if you added `stack.push( i );` before/after `stack.push( value[ i ] );`? – chacham15 Jul 06 '14 at 20:52
  • 2
    Congratz for the effort, however I just tested this `roughSizeOfObject(document.createElement('div'));` and I got `999694` which is nearly 1MB. If one div was 1MB in memory then I wonder how much memory this page would need `:D`. Jokes aside, it returns the same values for `window` and `document` as well, so there must be something wrong. Cheers! – php_nub_qq Sep 04 '14 at 13:36
  • this function takes at least 1 minute to analyze a Parse.Object. The result is 3.5 MB. any idea how to optimize the function? – otmezger Sep 09 '14 at 20:52
  • 2
    'Your object is roughly: ' + (JSON.stringify(obj).length * 4 / 1024 / 1024) + 'mb' + ' one utf8 glyph can be at max 4 bytes, this number is usually fairly accurate.'; – Adrian Seeley Oct 18 '14 at 12:00
  • 1
    somebody can explain why is using 4 bits for boolean? I didn't find the boolean length in the ecma.. – rahpuser Dec 15 '14 at 15:29
  • I'm also curious about the 4 bytes for a boolean. ECMA doesn't really specify the size of a boolean but I can't think of a reason to not use only one byte. – kunigami May 17 '15 at 18:55
  • @abuduba do you know how to add weakmap suport? – thomas-peter Mar 16 '16 at 09:55
  • 1
    I'll make a dictionary with all primitive sizes and instead of if elsing a bunch of times I'll do `bytes += sizes[typeof value]`, what do you think? – julian Aug 03 '16 at 18:06
  • 1
    I think this is only counting values and not the object keys or other object metadata: ``` roughSizeOfObject(this._index) 29212 roughSizeOfObject(_.keys(this._index)) 144104 roughSizeOfObject(_.values(this._index)) 29212 ``` – Bee Wilkerson Jun 06 '17 at 14:30
  • 1
    You can now change the `objectList` to a `Set` to reduce lookup time for deeply nested objects. – Patrick Roberts Jan 21 '18 at 03:26
  • 1
    Too bad there's no a `sizeOf()` function in JS. I guess it's because it depends a lot of the client system. But for optimizing the code it's cool to be able to know the precise size, it saves time. (js coders usually don't care about memory, but when you work in really limited embedded systems, you need to care about it). – BuzzRage Apr 24 '18 at 15:44
  • 1
    This does not appear to take into account any of the overhead for each object, i.e., the references to each object, which would be at least one word per object. – David R Tribble Jul 16 '18 at 14:55
  • @Adrian Seeley Input: `{a: 1}`. Output from answer: `0.000008`. Output from `JSON.stringify` version: `0.000026702880859375mb` – explorer Apr 09 '19 at 07:31
  • 1
    & Chrome developer tools said: 0.000029999999999999997 – explorer Apr 09 '19 at 08:11
  • 1
    @php_nub_qq I realize this is an extremely late response... Every div has the property `ownerDocument`, which is `document`. `document` has the property `defaultView` which is usually `window`. So calculating the size of window vs document vs a random div is going to traverse basically the same objects. – Joseph Dykstra Jul 12 '19 at 20:13
  • There is one more issue - it doesn't take into account that strings are immutable objects and copied by ref. In use case where string constants are extensively used, value calculated by this function will differ significantly from the real. For example `[{type: 'video', subtype: 'youtube', ...}, {type: 'video', subtype: 'vimeo', ...}, {type: 'img', subtype: 'jpg', ...}, {type: 'img', subtype: 'svg', ...}, {type: 'image', subtype: 'gif', ...}, ...]`. In this example properties `type` and `subtype` of different objects MAY point to the same objects in memory. – Maxim Kulikov Jul 14 '19 at 08:30
  • 1
    This code does not take internal object data into account. Object is an instance of a class. So it has links to the prototype. All properties have their configuration (see Object.create). And what about methods? How large are they? Internal data structure (usually a hash map implementation) occupies additional space. The size of variables in memory depends on JS engine you are running. So are optimizations... – Anton Rusak Oct 31 '19 at 10:54
  • This code can be used to (roughly) compare very simple data structures. Not to calculate the real size of complex objects. You should use low-level tools like profilers to see what really happens. – Anton Rusak Oct 31 '19 at 10:54
  • Anton, I agree. When I wrote this, there were no such tools. However, if you want to be able to check the size in your code at runtime, ie not profiling, I would still be interested if you were to think of something that could be added. – thomas-peter Nov 01 '19 at 11:32
  • This does not factor in string interning – Steven Wexler Nov 13 '19 at 02:53
  • Updating inner for to be ```for( var i in value ) { bytes += i.length * 2; stack.push( value[ i ] ); }``` should count the keys? – Pumych Jan 04 '20 at 20:57
  • This gives me the error `[Exception... "Method not implemented" nsresult: "0x80004001 (NS_ERROR_NOT_IMPLEMENTED)" location: "JS frame :: debugger eval code :: roughSizeOfObject :: line 28" data: no]` on the `stack.push` line. Not sure since when Firefox has an issue pushing elements to arrays :s – Luc May 09 '20 at 22:22
139

The Google Chrome Heap Profiler allows you to inspect object memory use.

You need to be able to locate the object in the trace which can be tricky. If you pin the object to the Window global, it is pretty easy to find from the "Containment" listing mode.

In the attached screenshot, I created an object called "testObj" on the window. I then located in the profiler (after making a recording) and it shows the full size of the object and everything in it under "retained size".

More details on the memory breakdowns.

Chrome profiler

In the above screenshot, the object shows a retained size of 60. I believe the unit is bytes here.

James Skemp
  • 7,386
  • 9
  • 58
  • 95
Guy Bedford
  • 1,765
  • 1
  • 13
  • 4
  • 14
    This answer solved my problem along with : https://developers.google.com/chrome-developer-tools/docs/heap-profiling . Quick tip : take a quick Heap Snapshot, run the task you suspect is leaking, take a new quick Heap Snapshot and select the `comparison` view at the bottom. It makes obvious what objects were created between the two snapshots. – Johnride Mar 28 '14 at 15:13
  • Comparison, mentioned by @Johnride, is now a pulldown menu at the top. – frandroid Apr 07 '16 at 18:42
  • `Shallow size` seems as 40 for both of `{ a:"55c2067aee27593c03b7acbe", b:"55c2067aee27593c03b7acbe", c:null, d:undefined }` and `{ c:null, d:undefined }` objects. Is it OK? – efkan Apr 04 '17 at 14:58
  • 2
    You can use the Google Chrome Heap Profiler from node too. If you have node v8 or above start it with `node --inspect` and in Chrome enter `about:inspect` in the URL bar and look for opening the Node inspector. Create your object in the node CLI and then take a heap snapshot. – Gregor Sep 18 '18 at 11:42
77

I just wrote this to solve a similar (ish) problem. It doesn't exactly do what you may be looking for, ie it doesn't take into account how the interpreter stores the object.

But, if you are using V8, it should give you a fairly ok approximation as the awesome prototyping and hidden classes lick up most of the overhead.

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 );
}
thomas-peter
  • 6,952
  • 6
  • 37
  • 56
65

Sometimes I use this to flag really big objects that might be going to the client from the server. It doesn't represent the in memory footprint. It just gets you approximately what it'd cost to send it, or store it.

Also note, it's slow, dev only. But for getting an ballpark answer with one line of code it's been useful for me.

roughObjSize = JSON.stringify(bigObject).length;
zstew
  • 919
  • 7
  • 11
  • 2
    From my tests, this method is considerably faster than the object-sizeof case because it doesn't have the slow _.isObject() call from lodash. In addition the sizes returned are pretty comparable for rough estimates. Gist https://gist.github.com/owenallenaz/ff77fc98081708146495 . – Nucleon Sep 29 '15 at 21:48
  • 3
    Too bad [it breaks up when object is too big](https://github.com/nodejs/node-v0.x-archive/issues/14170). :( – cregox Nov 30 '15 at 10:51
  • 5
    Can't use with circular structures `VM1409:1 Uncaught TypeError: Converting circular structure to JSON` :( still useful though – givanse Oct 14 '16 at 18:24
  • this is not binary size in bytes but simple to use to get approximate size – datdinhquoc Feb 20 '19 at 02:59
  • This is pretty great if 1) you only need a ballpark estimate 2) you know you don't have any circular references 3) you can omit large values and messure them separately. All of these were true in my case so works perfectly, I only had one big string at one place which I can just measure length on. – OZZIE Mar 20 '19 at 10:43
54

Here's a slightly more compact solution to the problem:

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);
Dan
  • 1,870
  • 16
  • 28
  • 3
    so this is the size in KB? or bits? – vincent thorpe Dec 06 '17 at 00:00
  • 2
    @vincent-thorpe It's in bytes. – Dan Dec 07 '17 at 16:43
  • 3
    Nice script, needs modifications for cyclic references though. – Jim Pedid Feb 08 '18 at 19:22
  • 2
    I've just tested your algorithm on a huge array of data within a node process, it reports 13GB, but node is consuming 22GB, any idea about where the difference comes from? There is nothing more in memory. – Josu Goñi Mar 24 '18 at 22:03
  • 5
    @JosuGoñi, they don't calculate how much the object itself takes, only its value. All objects take more space than just their value, otherwise `typeof ...` would not work. – Alexis Wilke Dec 27 '18 at 10:19
  • so i assume that strings take up 2 bytes per character? – shieldgenerator7 Nov 22 '19 at 03:22
  • Each one of these will take more bytes because it's using raw C sizes. In JS a 64 bit number isn't just 64bit but at least everything will be +8 bytes, for value AND type. Taking that into account you're still only going to get a rough figure. – jgmjgm Jan 22 '20 at 19:27
51

There is a NPM module to get object sizeof, you can install it with 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));
reformed
  • 3,922
  • 9
  • 51
  • 77
Andrei Karpushonak
  • 8,338
  • 1
  • 36
  • 50
  • sizeof(new Date()) === 0 and sizeof({}) === 0. Is that intended? – Philipp Claßen May 24 '18 at 12:59
  • 1
    @PhilippClaßen Obviously it is. Both objects have no properties. – Robert Feb 06 '20 at 00:09
  • 1
    This doesn't seem too useful. It provides some theoretical number akin to C `sizeof` semantics, but not the actual amount of memory used. Objects themselves consume space (so `sizeof(new Date())` should be >0), and JS engines save memory by deduping strings and storing them in single-byte encodings when possible, for example. – ZachB Aug 18 '20 at 19:38
  • @Robert @Philipp Claßen But an empty object still occupies memory space. It has at least a refecente to it's prototype (the `__proto__` implicit property) and probably others I'm not aware of. And, in the case of the `Date` object, it has at least the reference to the moment of time it refers to. `sizeof` can't read it's properties because `Date` is written in native code. Also, `sizeof` [uses for ... in](https://github.com/lyroyce/sizeof/blob/master/lib/sizeof.js#L22) loop to read object properties so it also don't count symbol properties and private fields. – Leonardo Raele Jan 12 '21 at 22:05
18

This is a hacky method, but i tried it twice with different numbers and it seems to be consistent.

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

I tried this in my computer and the process had 48352K of memory when the "before" alert was shown. After the allocation, Firefox had 440236K of memory. For 2million allocations, this is about 200 bytes for each object.

I tried it again with 1million allocations and the result was similar: 196 bytes per object (i suppose the extra data in 2mill was used for Array).

So, here is a hacky method that might help you. JavaScript doesn't provide a "sizeof" method for a reason: each JavaScript implementaion is different. In Google Chrome for example the same page uses about 66 bytes for each object (judging from the task manager at least).

Community
  • 1
  • 1
Bad Sector
  • 722
  • 1
  • 6
  • 10
  • Hey.. thanks for the technique. I was having that as plan B incase no direct way was there to measure memory usage. –  Aug 08 '09 at 10:38
  • 4
    Each C and C++ implementation is also different. ;) The size of a data type in C or C++ is implementation specific. I see no reason JavaScript couldn't support such an operator, though it wouldn't serve the same purpose or have the same meaning as it does in C or C++ (which are lower-level languages and measure the actual size of a fixed-size data type at compile time as opposed to the variable-size of a dynamic JavaScript object at run-time). – bambams Oct 21 '09 at 17:48
12

Having the same problem. I searched on Google and I want to share with stackoverflow community this solution.

Important:

I used the function shared by Yan Qing on 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);

What do you think about it?

Ala Eddine JEBALI
  • 4,649
  • 3
  • 35
  • 48
12

Sorry I could not comment, so I just continue the work from tomwrong. This enhanced version will not count object more than once, thus no infinite loop. Plus, I reckon the key of an object should be also counted, roughly.

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);
Liangliang Zheng
  • 1,663
  • 11
  • 16
  • I think this is more accurate as it's counting keys, although it does count the '_\_visited_\_' key – Sam Hasler Mar 05 '13 at 16:34
  • Checking `typeof value === 'object'`is not enough and you'll have exceptions if the value is `null`. – floribon May 29 '14 at 18:59
  • This was blazing fast for my object (which I'm pretty confident have way over 5mb), in comparison with any of @tomwrong's duped answers. It was also more accurate (as it said 3mb or so) but still way too far from reality. Any clues on what it may not be counting? – cregox Nov 30 '15 at 10:54
  • Doesn't work for me. Object `level` contains data but `roughSizeOfObject(level)` returns zero. (My variable level is not to be confused with your argument, of course. I don't think that variable shadowing should cause an issue here, and also when I rename the 'level' in your script I get the same result.) Screenshot: https://snipboard.io/G7E5yj.jpg – Luc May 09 '20 at 22:48
7

i want to know if my memory reduction efforts actually help in reducing memory

Following up on this comment, here's what you should do: Try to produce a memory problem - Write code that creates all these objects and graudally increase the upper limit until you ran into a problem (Browser crash, Browser freeze or an Out-Of-memory error). Ideally you should repeat this experiment with different browsers and different operating system.

Now there are two options: option 1 - You didn't succeed in producing the memory problem. Hence, you are worrying for nothing. You don't have a memory issue and your program is fine.

option 2- you did get a memory problem. Now ask yourself whether the limit at which the problem occurred is reasonable (in other words: is it likely that this amount of objects will be created at normal use of your code). If the answer is 'No' then you're fine. Otherwise you now know how many objects your code can create. Rework the algorithm such that it does not breach this limit.

Itay Maman
  • 28,289
  • 9
  • 76
  • 114
  • From a memory stand point, my extension adds a number of objects for each page/tab that is open in Firefox. The "number" is proportional to the size of the page. Assuming that "power" users have anywhere between 15 - 20 tabs open, and if the web page has a lot of contents, the browser becomes slow and frustratingly non-responsive after some time. This happens even without me explicitly trying to stress the app. I have plans to rewrite the code that I think will reduce a lot of object creation. I just wanted to be sure that the no. of objects reduced amounted to something so that it is worth it –  Aug 08 '09 at 10:37
  • @Senthil: but object size has no meaning unless you know amount of available memory. Since amount of memory is likely to remain a mystery, speaking in terms of #objects is just as useful as speaking in term of #bytes – Itay Maman Aug 08 '09 at 14:08
6

This Javascript library sizeof.js does the same thing. Include it like this

<script type="text/javascript" src="sizeof.js"></script>

The sizeof function takes an object as a parameter and returns its approximate size in bytes. For example:

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

The sizeof function can handle objects that contain multiple references to other objects and recursive references.

Originally published here.

Jayram
  • 16,472
  • 6
  • 46
  • 66
5

If your main concern is the memory usage of your Firefox extension, I suggest checking with Mozilla developers.

Mozilla provides on its wiki a list of tools to analyze memory leaks.

Vincent Robert
  • 33,284
  • 13
  • 77
  • 115
4

Chrome developer tools has this functionality. I found this article very helpful and does exactly what you want: https://developers.google.com/chrome-developer-tools/docs/heap-profiling

benja2729
  • 85
  • 2
2

Many thanks to everyone that has been working on code for this!

I just wanted to add that I've been looking for exactly the same thing, but in my case it's for managing a cache of processed objects to avoid having to re-parse and process objects from ajax calls that may or may not have been cached by the browser. This is especially useful for objects that require a lot of processing, usually anything that isn't in JSON format, but it can get very costly to keep these things cached in a large project or an app/extension that is left running for a long time.

Anyway, I use it for something something like:

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

It's a simplistic example and may have some errors, but it gives the idea, as you can use it to hold onto static objects (contents won't change) with some degree of intelligence. This can significantly cut down on any expensive processing requirements that the object had to be produced in the first place.

Haravikk
  • 2,658
  • 1
  • 24
  • 40
1

I use Chrome dev tools' Timeline tab, instantiate increasingly large amounts of objects, and get good estimates like that. You can use html like this one below, as boilerplate, and modify it to better simulate the characteristics of your objects (number and types of properties, etc...). You may want to click the trash bit icon at the bottom of that dev tools tab, before and after a run.

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

Instantiating 2 million objects of just one property each (as in this code above) leads to a rough calculation of 50 bytes per object, on my Chromium, right now. Changing the code to create a random string per object adds some 30 bytes per object, etc. Hope this helps.

matanster
  • 13,785
  • 14
  • 75
  • 135
1

If you need to programatically check for aprox. size of objects you can also check this library http://code.stephenmorley.org/javascript/finding-the-memory-usage-of-objects/ that I have been able to use for objects size.

Otherwise I suggest to use the Chrome/Firefox Heap Profiler.

Alex M
  • 31
  • 3
1
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;
}
0

Building upon the already compact solution from @Dan, here's a self-contained function version of it. Variable names are reduced to single letters for those who just want it to be as compact as possible at the expense of context.

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));
OXiGEN
  • 995
  • 13
  • 13
-3

I believe you forgot to 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";
        }
    },
  • 1
    In JS, an array is an object. There may be some optimizations in implementations, but conceptually arrays and objects are the same. – Kris Walker Nov 20 '11 at 10:15
-7

I know this is absolutely not the right way to do it, yet it've helped me a few times in the past to get the approx object file size:

Write your object/response to the console or a new tab, copy the results to a new notepad file, save it, and check the file size. The notepad file itself is just a few bytes, so you'll get a fairly accurate object file size.

Jeffrey Roosendaal
  • 5,961
  • 8
  • 33
  • 50