- Main question: whether to store a data table as array of row objects, or as an object of column arrays.
- Proximate question: How to measure the memory footprint of an object.
- Practical question: How do I read the memory profiler in Chrome?
Background
Working with rectangular data tables in Javascript, both in browser and/or Node.js. Many leading libraries like D3 and Crossfilter store data as arrays of objects, e.g.
var rows =
[{name: 'apple', price: 1.79, ...},
{name: 'berry', price: 3.49, ...},
{name: 'cherry', price: 4.29, ...}, ...
]
However, it seems with many columns (my use case) and potentially many rows, the overhead of storing keys can become very heavy, and it would be more efficient to store the data (and iterate over it) storing each column as an array, as in:
var cols = {
name: ['apple', 'berry', 'cherry', ...],
price: [1.79, 3.49, 4.29, ...],
...
}
Profiling question
One answer to this post describes using the Chrome memory profile: JavaScript object size
I set up the following simplistic benchmark below. The code can be copied/pasted to the console of Chrome and executed. I then looked at the Chrome profiler, but not sure how to read it.
At first glance, the retained size seems clearly in favor of columns:
window.rowData: 294,170,760 bytes
window.colData: 44,575,896 bytes
But if I click on each, they give me the same (huge) retained size:
window.rowData
:338,926,668 bytes
window.colData
:338,926,668 bytes
Benchmark code
The following code can be copy/pasted to Chrome console:
function makeid(len) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < len; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
/* create set of 400 string keys with 8 random characters.*/
var keys = window.keys = [], i, c;
for ( i=0; i < 400; i++) {
keys.push(makeid(8));
}
/* METHOD 1: Create array of objects with {colName: cellValue} pairs */
var rows = window.rowData = [];
for ( i = 0; i < 10000; i++) {
var row = {};
for ( c = 0; c < 400; c++) {
row[keys[c]] = Math.random();
}
rows.push(row);
}
/* METHOD 2: Create set of columns { colName: [values]} */
var cols = window.colData = {};
for ( c=0; c<400; c++) {
var col = cols[keys[c]] = [];
for ( i=0; i<10000; i++) {
col[i] = rows[i][keys[c]];
}
}