Skip to content

运行时性能优化

内存管理

内存生命周期

  1. 分配内存:JavaScript引擎分配内存
  2. 使用内存:读写内存中的数据
  3. 释放内存:垃圾回收器回收不再使用的内存

内存泄漏

常见内存泄漏

  1. 未清理的定时器
javascript
// 不好的做法:未清理定时器
function startTimer() {
  setInterval(() => {
    console.log('定时器运行中');
  }, 1000);
}

// 好的做法:清理定时器
let timer;
function startTimer() {
  timer = setInterval(() => {
    console.log('定时器运行中');
  }, 1000);
}

function stopTimer() {
  clearInterval(timer);
}
  1. 未清理的事件监听器
javascript
// 不好的做法:未清理事件监听器
function setupListeners() {
  const element = document.getElementById('button');
  element.addEventListener('click', function() {
    console.log('点击事件');
  });
}

// 好的做法:清理事件监听器
let element;
let clickHandler;

function setupListeners() {
  element = document.getElementById('button');
  clickHandler = function() {
    console.log('点击事件');
  };
  element.addEventListener('click', clickHandler);
}

function cleanupListeners() {
  if (element && clickHandler) {
    element.removeEventListener('click', clickHandler);
    element = null;
    clickHandler = null;
  }
}
  1. 闭包导致的内存泄漏
javascript
// 不好的做法:闭包导致的内存泄漏
function createClosure() {
  const largeArray = new Array(1000000).fill('data');
  
  return function() {
    console.log('闭包函数');
  };
}

const leakyFunction = createClosure();

// 好的做法:避免不必要的闭包
function createClosure() {
  return function() {
    console.log('闭包函数');
  };
}

const safeFunction = createClosure();
  1. 未清理的DOM引用
javascript
// 不好的做法:未清理的DOM引用
const elements = [];

function addElements() {
  for (let i = 0; i < 100; i++) {
    const element = document.createElement('div');
    elements.push(element);
    document.body.appendChild(element);
  }
}

function removeElements() {
  // 只从DOM中移除,未从数组中移除
  elements.forEach(element => {
    document.body.removeChild(element);
  });
}

// 好的做法:清理DOM引用
function removeElements() {
  elements.forEach(element => {
    document.body.removeChild(element);
  });
  elements.length = 0; // 清空数组
}
  1. 循环引用
javascript
// 不好的做法:循环引用
function createCircularReference() {
  const obj1 = {};
  const obj2 = {};
  
  obj1.ref = obj2;
  obj2.ref = obj1;
  
  return '循环引用创建';
}

// 好的做法:避免循环引用
function createSafeReference() {
  const obj1 = {};
  const obj2 = {};
  
  obj1.ref = obj2;
  // 不创建循环引用
  
  return '安全引用创建';
}

内存泄漏检测

使用Chrome DevTools

  1. Memory面板

    • 选择"Heap snapshot"(堆快照)
    • 点击"Take snapshot"(拍摄快照)
    • 执行可能导致内存泄漏的操作
    • 再次拍摄快照
    • 比较两个快照,查看增加的对象
  2. Performance面板

    • 选择"Memory"(内存)
    • 点击录制按钮
    • 执行操作
    • 停止录制
    • 查看内存使用曲线

垃圾回收

垃圾回收算法

  1. 标记-清除算法

    • 标记不再使用的对象
    • 清除被标记的对象
    • 整理内存碎片
  2. 引用计数算法

    • 跟踪每个对象的引用计数
    • 当引用计数为0时,回收对象
    • 无法处理循环引用
  3. 分代回收

    • 新生代:短期对象,使用Scavenge算法
    • 老生代:长期对象,使用标记-清除算法

触发垃圾回收

javascript
// 手动触发垃圾回收(仅开发环境)
if (typeof gc === 'function') {
  gc();
  console.log('垃圾回收已触发');
}

// 避免内存泄漏的最佳实践
function cleanup() {
  // 清理定时器
  clearInterval(timer);
  
  // 清理事件监听器
  element.removeEventListener('click', handler);
  
  // 清理DOM引用
  element = null;
  handler = null;
  
  // 清理数组
  array.length = 0;
  
  // 清理对象
  for (const key in object) {
    delete object[key];
  }
}
加载中...

好好学习,天天向上