寫個方法近似計算指定陣列或物件佔用記憶體的大小

王铁柱6發表於2024-12-04
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.

相關文章