跳到主要内容

性能与监控✅

本主题涵盖Node.js在生产环境中的性能监控、错误处理和内存优化等关键技术。

什么是负载?如何查看Node.js运行负载?

答案

核心概念:

负载(Load)是指系统在特定时间内正在运行和等待运行的进程数量。在Node.js中,监控负载包括CPU使用率、内存占用、事件循环延迟等关键指标。

监控方法:

Node.js提供了多种方式来监控系统和进程负载:

系统负载监控:

  • os.loadavg() - 获取系统1分钟、5分钟、15分钟的平均负载
  • os.cpus() - 获取CPU核心信息
  • os.totalmem() / os.freemem() - 获取内存信息

进程负载监控:

  • process.memoryUsage() - Node.js进程内存使用情况
  • process.cpuUsage() - 进程CPU使用时间
  • process.uptime() - 进程运行时间

示例代码:

// Node.js 负载监控示例
const os = require('os');
const cluster = require('cluster');

// 1. CPU 负载监控
function getCPULoad() {
  console.log('=== CPU 负载信息 ===');
  
  // 获取CPU核心数
  const cpuCount = os.cpus().length;
  console.log(`CPU 核心数: ${cpuCount}`);
  
  // 获取系统负载平均值
  const loadavg = os.loadavg();
  console.log(`系统负载 (1分钟): ${loadavg[0].toFixed(2)}`);
  console.log(`系统负载 (5分钟): ${loadavg[1].toFixed(2)}`);
  console.log(`系统负载 (15分钟): ${loadavg[2].toFixed(2)}`);
  
  // 负载率计算 (负载/核心数)
  const loadRate = (loadavg[0] / cpuCount * 100).toFixed(2);
  console.log(`负载率: ${loadRate}%`);
}

// 2. 内存使用监控
function getMemoryUsage() {
  console.log('\n=== 内存使用信息 ===');
  
  // 系统内存
  const totalMem = os.totalmem();
  const freeMem = os.freemem();
  const usedMem = totalMem - freeMem;
  
  console.log(`系统总内存: ${(totalMem / 1024 / 1024 / 1024).toFixed(2)} GB`);
  console.log(`系统空闲内存: ${(freeMem / 1024 / 1024 / 1024).toFixed(2)} GB`);
  console.log(`系统已用内存: ${(usedMem / 1024 / 1024 / 1024).toFixed(2)} GB`);
  console.log(`内存使用率: ${(usedMem / totalMem * 100).toFixed(2)}%`);
  
  // Node.js 进程内存
  const memUsage = process.memoryUsage();
  console.log('\n--- Node.js 进程内存 ---');
  console.log(`RSS (物理内存): ${(memUsage.rss / 1024 / 1024).toFixed(2)} MB`);
  console.log(`Heap Used (堆已用): ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)} MB`);
  console.log(`Heap Total (堆总计): ${(memUsage.heapTotal / 1024 / 1024).toFixed(2)} MB`);
  console.log(`External (外部内存): ${(memUsage.external / 1024 / 1024).toFixed(2)} MB`);
}

// 3. 进程负载监控
function getProcessLoad() {
  console.log('\n=== 进程负载信息 ===');
  
  // 进程运行时间
  const uptime = process.uptime();
  console.log(`进程运行时间: ${(uptime / 3600).toFixed(2)} 小时`);
  
  // CPU 使用时间
  const cpuUsage = process.cpuUsage();
  console.log(`用户 CPU 时间: ${(cpuUsage.user / 1000).toFixed(2)} ms`);
  console.log(`系统 CPU 时间: ${(cpuUsage.system / 1000).toFixed(2)} ms`);
  
  // 事件循环延迟(简单估算)
  const start = Date.now();
  setImmediate(() => {
    const delay = Date.now() - start;
    console.log(`事件循环延迟: ${delay} ms`);
  });
}

// 4. 实时监控函数
function startMonitoring(interval = 5000) {
  console.log(`开始监控,间隔: ${interval}ms`);
  console.log('按 Ctrl+C 停止监控\n');
  
  const monitor = () => {
    console.clear();
    console.log(`=== Node.js 负载监控 (${new Date().toLocaleString()}) ===`);
    
    getCPULoad();
    getMemoryUsage();
    getProcessLoad();
    
    console.log('\n' + '='.repeat(50));
  };
  
  // 立即执行一次
  monitor();
  
  // 定时监控
  const timer = setInterval(monitor, interval);
  
  // 优雅关闭
  process.on('SIGINT', () => {
    clearInterval(timer);
    console.log('\n监控已停止');
    process.exit(0);
  });
}

// 执行监控
if (require.main === module) {
  startMonitoring(3000);
}

module.exports = {
  getCPULoad,
  getMemoryUsage,
  getProcessLoad,
  startMonitoring
};

生产环境最佳实践:

  • 设置负载报警阈值(通常CPU负载率>80%)
  • 定期监控内存泄漏趋势
  • 监控事件循环延迟,避免阻塞
  • 使用PM2或类似工具进行进程管理

面试官视角:

该题考察候选人对Node.js性能监控的理解:

  • 要点清单: 了解负载概念;掌握监控API使用;能设计监控方案;理解关键指标含义
  • 加分项: 有生产环境监控经验;了解性能调优方法;能预防性能问题;有完整的监控体系
  • 常见失误: 只知道基础API;不理解指标含义;缺乏实战经验;忽视监控的重要性

延伸阅读:

Node.js有哪些错误类型,如何捕获错误?

答案

核心概念:

Node.js中的错误可以分为JavaScript标准错误、系统错误、用户定义错误等类型。掌握不同错误的特点和捕获方法是构建稳定应用的基础。

错误类型分类:

1. JavaScript标准错误:

  • Error - 通用错误基类
  • SyntaxError - 语法错误
  • TypeError - 类型错误
  • ReferenceError - 引用错误
  • RangeError - 范围错误

2. Node.js系统错误:

  • ENOENT - 文件或目录不存在
  • EACCES - 权限被拒绝
  • EMFILE - 打开文件过多
  • EADDRINUSE - 地址已被使用

3. 异步错误:

  • Promise rejection
  • EventEmitter错误
  • 回调函数错误

示例代码:

// Node.js 错误类型和捕获示例
const fs = require('fs').promises;
const EventEmitter = require('events');

// 1. JavaScript 标准错误类型
function demonstrateJSErrors() {
  console.log('=== JavaScript 标准错误类型 ===');
  
  try {
    // SyntaxError - 语法错误
    console.log('SyntaxError 示例:');
    // eval('let x = ;'); // 取消注释会抛出 SyntaxError
    
    // TypeError - 类型错误
    console.log('TypeError 示例:');
    const obj = null;
    // obj.someMethod(); // 取消注释会抛出 TypeError
    
    // ReferenceError - 引用错误
    console.log('ReferenceError 示例:');
    // console.log(undefinedVariable); // 取消注释会抛出 ReferenceError
    
    // RangeError - 范围错误
    console.log('RangeError 示例:');
    const arr = new Array(-1); // 会抛出 RangeError
    
  } catch (error) {
    console.log(`捕获到错误: ${error.name} - ${error.message}`);
  }
}

// 2. Node.js 系统错误
async function demonstrateSystemErrors() {
  console.log('\n=== Node.js 系统错误 ===');
  
  try {
    // ENOENT - 文件或目录不存在
    await fs.readFile('nonexistent-file.txt', 'utf8');
  } catch (error) {
    console.log(`系统错误: ${error.code} - ${error.message}`);
    console.log(`错误路径: ${error.path}`);
    console.log(`系统调用: ${error.syscall}`);
  }
  
  try {
    // EACCES - 权限拒绝
    await fs.access('/root/restricted-file', fs.constants.F_OK);
  } catch (error) {
    if (error.code === 'EACCES') {
      console.log('权限被拒绝');
    }
  }
}

// 3. Promise 错误处理
async function demonstratePromiseErrors() {
  console.log('\n=== Promise 错误处理 ===');
  
  // Promise.reject() 错误
  try {
    await Promise.reject(new Error('Promise rejected'));
  } catch (error) {
    console.log(`Promise 错误: ${error.message}`);
  }
  
  // 未处理的 Promise rejection
  const unhandledPromise = Promise.reject(new Error('未处理的 Promise 错误'));
  
  // 捕获未处理的 rejection
  process.on('unhandledRejection', (reason, promise) => {
    console.log('未处理的 Promise rejection:', reason.message);
    console.log('Promise:', promise);
    
    // 在生产环境中应该记录错误并优雅关闭
    // process.exit(1);
  });
}

// 4. EventEmitter 错误处理
function demonstrateEventEmitterErrors() {
  console.log('\n=== EventEmitter 错误处理 ===');
  
  const emitter = new EventEmitter();
  
  // 监听错误事件
  emitter.on('error', (error) => {
    console.log(`EventEmitter 错误: ${error.message}`);
  });
  
  // 触发错误
  emitter.emit('error', new Error('EventEmitter 发生错误'));
  
  // 如果没有错误监听器,会抛出错误
  const emitter2 = new EventEmitter();
  try {
    emitter2.emit('error', new Error('无监听器的错误'));
  } catch (error) {
    console.log(`未监听的 EventEmitter 错误: ${error.message}`);
  }
}

// 5. 自定义错误类
class CustomError extends Error {
  constructor(message, code, statusCode = 500) {
    super(message);
    this.name = 'CustomError';
    this.code = code;
    this.statusCode = statusCode;
    
    // 保持堆栈跟踪
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, CustomError);
    }
  }
}

class ValidationError extends CustomError {
  constructor(message, field) {
    super(message, 'VALIDATION_ERROR', 400);
    this.name = 'ValidationError';
    this.field = field;
  }
}

function demonstrateCustomErrors() {
  console.log('\n=== 自定义错误类 ===');
  
  try {
    throw new ValidationError('邮箱格式不正确', 'email');
  } catch (error) {
    if (error instanceof ValidationError) {
      console.log(`验证错误: ${error.message}`);
      console.log(`错误字段: ${error.field}`);
      console.log(`状态码: ${error.statusCode}`);
    }
  }
}

// 6. 全局错误处理
function setupGlobalErrorHandlers() {
  console.log('\n=== 全局错误处理设置 ===');
  
  // 捕获未处理的异常
  process.on('uncaughtException', (error) => {
    console.error('未捕获的异常:', error);
    
    // 记录错误后优雅关闭
    console.log('正在关闭服务器...');
    // 在实际应用中,应该:
    // 1. 记录错误到日志系统
    // 2. 通知监控系统  
    // 3. 优雅关闭服务器
    // process.exit(1);
  });
  
  // 捕获未处理的 Promise rejection
  process.on('unhandledRejection', (reason, promise) => {
    console.error('未处理的 Promise rejection:', reason);
    console.log('在 Promise:', promise);
    
    // 抛出异常让 uncaughtException 处理
    // throw reason;
  });
  
  // 进程退出处理
  process.on('SIGINT', () => {
    console.log('\n收到 SIGINT 信号,正在优雅关闭...');
    process.exit(0);
  });
  
  process.on('SIGTERM', () => {
    console.log('收到 SIGTERM 信号,正在优雅关闭...');
    process.exit(0);
  });
}

// 7. 错误监控和日志记录
class ErrorMonitor {
  constructor() {
    this.errorCounts = new Map();
    this.errorHistory = [];
  }
  
  logError(error, context = {}) {
    const errorInfo = {
      timestamp: new Date().toISOString(),
      name: error.name,
      message: error.message,
      stack: error.stack,
      code: error.code,
      context
    };
    
    // 记录错误
    this.errorHistory.push(errorInfo);
    
    // 统计错误次数
    const key = `${error.name}:${error.message}`;
    this.errorCounts.set(key, (this.errorCounts.get(key) || 0) + 1);
    
    console.log('错误已记录:', JSON.stringify(errorInfo, null, 2));
  }
  
  getErrorStats() {
    return {
      totalErrors: this.errorHistory.length,
      errorCounts: Object.fromEntries(this.errorCounts),
      recentErrors: this.errorHistory.slice(-5)
    };
  }
}

// 主函数
async function main() {
  console.log('Node.js 错误处理演示');
  console.log('====================\n');
  
  // 设置全局错误处理
  setupGlobalErrorHandlers();
  
  // 创建错误监控器
  const monitor = new ErrorMonitor();
  
  try {
    // 演示各种错误类型
    demonstrateJSErrors();
    await demonstrateSystemErrors();
    await demonstratePromiseErrors();
    demonstrateEventEmitterErrors();
    demonstrateCustomErrors();
    
    // 模拟一些错误并监控
    setTimeout(() => {
      try {
        throw new Error('定时器错误');
      } catch (error) {
        monitor.logError(error, { source: 'timer' });
      }
    }, 1000);
    
    // 输出错误统计
    setTimeout(() => {
      console.log('\n=== 错误统计 ===');
      console.log(JSON.stringify(monitor.getErrorStats(), null, 2));
    }, 2000);
    
  } catch (error) {
    monitor.logError(error, { source: 'main' });
  }
}

// 执行演示
if (require.main === module) {
  main().catch(console.error);
}

module.exports = {
  CustomError,
  ValidationError,
  ErrorMonitor,
  demonstrateJSErrors,
  demonstrateSystemErrors,
  demonstratePromiseErrors,
  demonstrateEventEmitterErrors,
  demonstrateCustomErrors,
  setupGlobalErrorHandlers
};

错误处理策略:

同步错误: 使用try-catch捕获 异步错误: 使用Promise.catch()或async/await + try-catch EventEmitter错误: 监听'error'事件 Stream错误: 使用pipeline()和错误处理中间件

面试官视角:

该题考察候选人的错误处理能力:

  • 要点清单: 熟悉各种错误类型;掌握捕获方法;理解异步错误处理;能设计错误监控
  • 加分项: 有生产环境错误处理经验;能设计错误恢复机制;了解错误监控系统;有错误分析能力
  • 常见失误: 只了解基础错误类型;不理解异步错误;缺乏全局错误处理;忽视错误监控

延伸阅读:

如何进行Node.js内存优化?

答案

核心概念:

Node.js内存优化涉及理解V8垃圾回收机制、识别内存泄漏、合理使用内存分配策略。掌握内存管理是构建高性能Node.js应用的关键。

V8垃圾回收机制:

分代回收策略:

  • 新生代(New Space): 存放短期对象,使用Scavenge算法快速回收
  • 老生代(Old Space): 存放长期对象,使用Mark-Sweep和Mark-Compact算法

垃圾回收过程:

  1. 新对象分配到新生代
  2. 经过2次垃圾回收仍存活的对象晋升到老生代
  3. 老生代空间不足时触发Mark-Sweep回收
  4. 内存碎片过多时执行Mark-Compact整理

内存优化实践:

// Node.js 内存优化示例
const { performance, PerformanceObserver } = require('perf_hooks');

// 1. 内存使用监控
function monitorMemoryUsage() {
  console.log('=== 内存使用监控 ===');
  
  const usage = process.memoryUsage();
  const formatBytes = (bytes) => (bytes / 1024 / 1024).toFixed(2) + ' MB';
  
  console.log(`RSS (常驻内存): ${formatBytes(usage.rss)}`);
  console.log(`Heap Used (堆内存使用): ${formatBytes(usage.heapUsed)}`);
  console.log(`Heap Total (堆内存总计): ${formatBytes(usage.heapTotal)}`);
  console.log(`External (外部内存): ${formatBytes(usage.external)}`);
  console.log(`Array Buffers (数组缓冲区): ${formatBytes(usage.arrayBuffers)}`);
  
  // 计算内存使用率
  const heapUsagePercent = ((usage.heapUsed / usage.heapTotal) * 100).toFixed(2);
  console.log(`堆内存使用率: ${heapUsagePercent}%`);
  
  return usage;
}

// 2. 垃圾回收监控
function setupGCMonitoring() {
  console.log('\n=== 垃圾回收监控 ===');
  
  const obs = new PerformanceObserver((list) => {
    const entries = list.getEntries();
    entries.forEach((entry) => {
      console.log(`GC ${entry.name}: ${entry.duration.toFixed(2)}ms`);
      console.log(`GC 类型: ${entry.detail ? entry.detail.kind : 'unknown'}`);
    });
  });
  
  obs.observe({ entryTypes: ['gc'] });
  
  // 主动触发垃圾回收 (需要 --expose-gc 参数)
  if (global.gc) {
    console.log('手动触发垃圾回收...');
    global.gc();
  } else {
    console.log('需要 --expose-gc 参数来启用手动垃圾回收');
  }
  
  return obs;
}

// 3. 内存泄漏演示和检测
class MemoryLeakDemo {
  constructor() {
    this.cache = new Map();
    this.listeners = [];
    this.timers = [];
  }
  
  // 演示常见的内存泄漏场景
  demonstrateMemoryLeaks() {
    console.log('\n=== 内存泄漏演示 ===');
    
    // 1. 缓存无限增长
    this.createUnboundedCache();
    
    // 2. 事件监听器未移除
    this.createUnremovedListeners();
    
    // 3. 定时器未清理
    this.createUnclearedTimers();
    
    // 4. 闭包引用
    this.createClosureReference();
  }
  
  createUnboundedCache() {
    console.log('创建无界限缓存 (模拟内存泄漏)...');
    
    // 模拟无限增长的缓存
    for (let i = 0; i < 10000; i++) {
      this.cache.set(`key_${i}`, {
        data: new Array(100).fill(`value_${i}`),
        timestamp: Date.now()
      });
    }
    
    console.log(`缓存大小: ${this.cache.size}`);
  }
  
  createUnremovedListeners() {
    console.log('创建未移除的事件监听器...');
    
    const EventEmitter = require('events');
    const emitter = new EventEmitter();
    
    // 创建多个未移除的监听器
    for (let i = 0; i < 100; i++) {
      const listener = () => console.log(`Listener ${i}`);
      emitter.on('test', listener);
      this.listeners.push({ emitter, event: 'test', listener });
    }
    
    console.log(`创建了 ${this.listeners.length} 个事件监听器`);
  }
  
  createUnclearedTimers() {
    console.log('创建未清理的定时器...');
    
    // 创建多个定时器但不清理
    for (let i = 0; i < 50; i++) {
      const timer = setInterval(() => {
        // 模拟一些工作
        const data = new Array(1000).fill(Math.random());
      }, 100);
      
      this.timers.push(timer);
    }
    
    console.log(`创建了 ${this.timers.length} 个定时器`);
  }
  
  createClosureReference() {
    console.log('创建闭包引用...');
    
    const largeData = new Array(10000).fill('large data chunk');
    
    // 闭包持有大对象的引用
    this.closureFunction = () => {
      return largeData.length;
    };
    
    console.log('闭包函数已创建,持有大对象引用');
  }
  
  // 清理内存泄漏
  cleanup() {
    console.log('\n=== 清理内存泄漏 ===');
    
    // 清理缓存
    this.cache.clear();
    console.log('缓存已清理');
    
    // 移除事件监听器
    this.listeners.forEach(({ emitter, event, listener }) => {
      emitter.removeListener(event, listener);
    });
    this.listeners = [];
    console.log('事件监听器已清理');
    
    // 清理定时器
    this.timers.forEach(timer => clearInterval(timer));
    this.timers = [];
    console.log('定时器已清理');
    
    // 清理闭包引用
    this.closureFunction = null;
    console.log('闭包引用已清理');
  }
}

// 4. 内存优化最佳实践
class MemoryOptimizer {
  // 对象池模式
  static createObjectPool(createFn, resetFn, initialSize = 10) {
    const pool = [];
    
    // 预填充对象池
    for (let i = 0; i < initialSize; i++) {
      pool.push(createFn());
    }
    
    return {
      get() {
        return pool.length > 0 ? resetFn(pool.pop()) : createFn();
      },
      
      release(obj) {
        if (pool.length < 100) { // 限制池大小
          pool.push(obj);
        }
      },
      
      size() {
        return pool.length;
      }
    };
  }
  
  // 流式处理大文件
  static async processLargeDataStream(data, batchSize = 1000) {
    console.log('\n=== 流式处理演示 ===');
    
    const results = [];
    for (let i = 0; i < data.length; i += batchSize) {
      const batch = data.slice(i, i + batchSize);
      
      // 处理批次数据
      const processed = batch.map(item => item * 2);
      results.push(...processed);
      
      // 在每个批次后检查内存
      if (i % (batchSize * 10) === 0) {
        const usage = process.memoryUsage();
        console.log(`处理进度: ${((i / data.length) * 100).toFixed(1)}%, 堆内存: ${(usage.heapUsed / 1024 / 1024).toFixed(2)}MB`);
        
        // 主动进行垃圾回收
        if (global.gc) {
          global.gc();
        }
      }
    }
    
    return results;
  }
  
  // 弱引用使用示例
  static demonstrateWeakReferences() {
    console.log('\n=== WeakMap/WeakSet 使用示例 ===');
    
    // 使用 WeakMap 避免内存泄漏
    const weakCache = new WeakMap();
    const strongCache = new Map();
    
    class User {
      constructor(name) {
        this.name = name;
      }
    }
    
    const users = [
      new User('Alice'),
      new User('Bob'),
      new User('Charlie')
    ];
    
    // 使用 WeakMap 存储用户相关数据
    users.forEach(user => {
      weakCache.set(user, { loginCount: 0, lastLogin: Date.now() });
      strongCache.set(user.name, user);
    });
    
    console.log(`WeakMap 大小: ${weakCache.has(users[0]) ? '包含用户数据' : '不包含用户数据'}`);
    console.log(`强引用缓存大小: ${strongCache.size}`);
    
    // 清除用户引用后,WeakMap 中的数据会被自动回收
    users.length = 0;
    
    // 强制垃圾回收
    if (global.gc) {
      global.gc();
    }
    
    console.log('用户引用清除后,WeakMap 数据将被自动回收');
  }
}

// 5. 内存监控工具
class MemoryMonitor {
  constructor(interval = 5000) {
    this.interval = interval;
    this.monitoring = false;
    this.history = [];
  }
  
  start() {
    if (this.monitoring) return;
    
    this.monitoring = true;
    console.log(`开始内存监控,间隔: ${this.interval}ms`);
    
    this.timer = setInterval(() => {
      const usage = process.memoryUsage();
      const timestamp = Date.now();
      
      this.history.push({ timestamp, usage });
      
      // 保持历史记录在合理范围内
      if (this.history.length > 100) {
        this.history.shift();
      }
      
      // 检测内存增长趋势
      this.checkMemoryGrowth();
    }, this.interval);
  }
  
  stop() {
    if (this.timer) {
      clearInterval(this.timer);
      this.monitoring = false;
      console.log('内存监控已停止');
    }
  }
  
  checkMemoryGrowth() {
    if (this.history.length < 5) return;
    
    const recent = this.history.slice(-5);
    const first = recent[0].usage.heapUsed;
    const last = recent[recent.length - 1].usage.heapUsed;
    const growthRate = ((last - first) / first) * 100;
    
    if (growthRate > 10) {
      console.warn(`警告: 内存增长过快 ${growthRate.toFixed(2)}%`);
      this.logCurrentUsage();
    }
  }
  
  logCurrentUsage() {
    const usage = process.memoryUsage();
    console.log('当前内存使用:');
    console.log(`  RSS: ${(usage.rss / 1024 / 1024).toFixed(2)} MB`);
    console.log(`  Heap Used: ${(usage.heapUsed / 1024 / 1024).toFixed(2)} MB`);
    console.log(`  Heap Total: ${(usage.heapTotal / 1024 / 1024).toFixed(2)} MB`);
  }
  
  getStats() {
    if (this.history.length === 0) return null;
    
    const usages = this.history.map(h => h.usage.heapUsed);
    const min = Math.min(...usages);
    const max = Math.max(...usages);
    const avg = usages.reduce((a, b) => a + b, 0) / usages.length;
    
    return {
      samples: this.history.length,
      minHeapUsed: (min / 1024 / 1024).toFixed(2) + ' MB',
      maxHeapUsed: (max / 1024 / 1024).toFixed(2) + ' MB',
      avgHeapUsed: (avg / 1024 / 1024).toFixed(2) + ' MB'
    };
  }
}

// 主函数演示
async function main() {
  console.log('Node.js 内存优化演示');
  console.log('=====================\n');
  
  // 1. 监控初始内存使用
  const initialUsage = monitorMemoryUsage();
  
  // 2. 设置垃圾回收监控
  const gcObserver = setupGCMonitoring();
  
  // 3. 演示内存泄漏
  const leakDemo = new MemoryLeakDemo();
  leakDemo.demonstrateMemoryLeaks();
  
  console.log('\n内存泄漏创建后:');
  monitorMemoryUsage();
  
  // 4. 清理内存泄漏
  setTimeout(() => {
    leakDemo.cleanup();
    
    if (global.gc) {
      global.gc();
    }
    
    console.log('\n清理后:');
    monitorMemoryUsage();
  }, 2000);
  
  // 5. 演示最佳实践
  setTimeout(async () => {
    // 对象池示例
    const numberPool = MemoryOptimizer.createObjectPool(
      () => ({ value: 0 }),
      (obj) => { obj.value = 0; return obj; }
    );
    
    console.log('\n=== 对象池演示 ===');
    const obj = numberPool.get();
    obj.value = 42;
    numberPool.release(obj);
    console.log(`对象池大小: ${numberPool.size()}`);
    
    // 流式处理演示
    const largeArray = new Array(50000).fill(0).map((_, i) => i);
    await MemoryOptimizer.processLargeDataStream(largeArray);
    
    // 弱引用演示
    MemoryOptimizer.demonstrateWeakReferences();
    
  }, 3000);
  
  // 6. 启动内存监控
  const monitor = new MemoryMonitor(1000);
  monitor.start();
  
  // 10秒后停止监控并输出统计
  setTimeout(() => {
    monitor.stop();
    const stats = monitor.getStats();
    console.log('\n=== 内存监控统计 ===');
    console.log(JSON.stringify(stats, null, 2));
    
    gcObserver.disconnect();
    process.exit(0);
  }, 10000);
}

// 执行演示
if (require.main === module) {
  main().catch(console.error);
}

module.exports = {
  monitorMemoryUsage,
  setupGCMonitoring,
  MemoryLeakDemo,
  MemoryOptimizer,
  MemoryMonitor
};

常见内存泄漏场景:

  • 无界限缓存增长: Map/Object缓存无清理机制
  • 事件监听器累积: EventEmitter监听器未移除
  • 定时器泄漏: setInterval/setTimeout未清理
  • 闭包引用: 闭包持有大对象引用

优化策略:

  • 使用对象池: 复用对象减少GC压力
  • 流式处理: 处理大数据时使用流避免全量加载
  • 弱引用: 使用WeakMap/WeakSet避免意外引用
  • 定期清理: 设置缓存过期和清理机制
  • 监控告警: 监控内存使用趋势设置告警

内存调优工具:

  • --inspect - Chrome DevTools调试
  • --trace-gc - 跟踪垃圾回收
  • --max-old-space-size - 调整老生代内存限制
  • heapdump - 生成内存快照分析

面试官视角:

该题考察候选人的内存管理能力:

  • 要点清单: 理解V8垃圾回收机制;能识别内存泄漏;掌握优化方法;有监控经验
  • 加分项: 深入理解GC算法;有大型应用内存调优经验;能设计内存监控系统;了解性能分析工具
  • 常见失误: 只知道表面概念;不理解GC原理;缺乏实际调优经验;忽视内存监控

延伸阅读: