function approximateMemorySize(obj) {
let bytes = 0;
function sizeOf(obj) {
if (obj !== null && obj !== undefined) {
switch (typeof obj) {
case 'number':
bytes += 8;
break;
case 'string':
bytes += obj.length * 2; // UTF-16, 2 bytes per character
break;
case 'boolean':
bytes += 4; // Could be 1, but using 4 for simplicity
break;
case 'object':
if (Array.isArray(obj)) {
// For arrays, iterate and add sizes of elements
for (let i = 0; i < obj.length; i++) {
sizeOf(obj[i]);
}
// Add memory for the array itself approximate array overhead
bytes += obj.length * 8; // Assuming pointers are 8 bytes (64-bit)
} else {
// For objects, iterate over properties
for (let key in obj) {
if (obj.hasOwnProperty(key)) { // Important to avoid inherited properties
bytes += key.length * 2; // Key string size
sizeOf(obj[key]); // Value size
}
}
// Add approximate object overhead
bytes += Object.keys(obj).length * 8; // Assuming pointers are 8 bytes
}
break;
}
}
}
sizeOf(obj);
return bytes;
}
// Examples
const myArray = [1, 2, "hello", true, { a: 1, b: "world" }];
const myObject = { name: "John Doe", age: 30, city: "New York" };
console.log(`Approximate size of myArray: ${approximateMemorySize(myArray)} bytes`);
console.log(`Approximate size of myObject: ${approximateMemorySize(myObject)} bytes`);
// More robust example handling more data types including cyclical references
function moreRobustSizeOf(obj, seen = new WeakSet()) {
let bytes = 0;
if (obj !== null && obj !== undefined && typeof obj === 'object') {
if (seen.has(obj)) return bytes; // Handle cyclical references
seen.add(obj);
}
switch (typeof obj) {
case 'number':
case 'bigint':
bytes += 8;
break;
case 'string':
bytes += obj.length * 2;
break;
case 'boolean':
bytes += 4;
break;
case 'symbol': // Symbols have unique sizes, approximating
bytes += 8;
break;
case 'function': // Functions are complex, rough estimate
bytes += 100; // Adjust as needed
break;
case 'object':
if (obj === null) break; // Null has no size
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
bytes += moreRobustSizeOf(obj[i], seen);
}
bytes += obj.length * 8;
} else {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
bytes += key.length * 2;
bytes += moreRobustSizeOf(obj[key], seen);
}
}
bytes += Object.keys(obj).length * 8;
}
break;
}
return bytes;
}
console.log(`More robust size of myArray: ${moreRobustSizeOf(myArray)} bytes`);
console.log(`More robust size of myObject: ${moreRobustSizeOf(myObject)} bytes`);
Key improvements and explanations in the more robust example:
- Handles Cyclical References: The
seen
WeakSet is used to track visited objects. If an object is encountered again, the function returns, preventing infinite recursion caused by cyclical references. - BigInt: Includes
bigint
which also typically uses 8 bytes. - Symbol: Provides an approximation for Symbols. Their actual size can vary.
- Function: Includes a very rough estimate for functions. The actual size is highly dependent on the function's content. This is just a placeholder and should be adjusted based on your specific needs.
- Null Handling: Explicitly handles
null
.