运行时性能优化
内存管理
内存生命周期
- 分配内存:JavaScript引擎分配内存
- 使用内存:读写内存中的数据
- 释放内存:垃圾回收器回收不再使用的内存
内存泄漏
常见内存泄漏
- 未清理的定时器
javascript
// 不好的做法:未清理定时器
function startTimer() {
setInterval(() => {
console.log('定时器运行中');
}, 1000);
}
// 好的做法:清理定时器
let timer;
function startTimer() {
timer = setInterval(() => {
console.log('定时器运行中');
}, 1000);
}
function stopTimer() {
clearInterval(timer);
}- 未清理的事件监听器
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;
}
}- 闭包导致的内存泄漏
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();- 未清理的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; // 清空数组
}- 循环引用
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
Memory面板:
- 选择"Heap snapshot"(堆快照)
- 点击"Take snapshot"(拍摄快照)
- 执行可能导致内存泄漏的操作
- 再次拍摄快照
- 比较两个快照,查看增加的对象
Performance面板:
- 选择"Memory"(内存)
- 点击录制按钮
- 执行操作
- 停止录制
- 查看内存使用曲线
垃圾回收
垃圾回收算法
标记-清除算法:
- 标记不再使用的对象
- 清除被标记的对象
- 整理内存碎片
引用计数算法:
- 跟踪每个对象的引用计数
- 当引用计数为0时,回收对象
- 无法处理循环引用
分代回收:
- 新生代:短期对象,使用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];
}
} 加载中...