优化内存的核心是方法共享与对象复用:将方法挂载到prototype避免重复创建,对大对象使用对象池管理;同时避免构造函数中频繁新建对象、正则、日期等。

构造函数本身不直接“分配大量内存”,真正吃内存的是实例对象——尤其是当每个实例都重复创建相同方法或大体积数据时。优化核心就两条:**方法共享 + 对象复用**,而不是每次都 new 一个全新副本。
把方法挂到 prototype 上,避免重复创建函数
每次调用构造函数,如果在 this 上直接赋值函数(比如 this.render = function() {...}),V8 就会为每个实例分配一份独立的函数对象,包含作用域、闭包、字节码等,开销不小。
正确做法是统一写在原型上:
function Chart(data) {
this.data = data; // 实例独有数据,放构造函数里
}
Chart.prototype.draw = function() { // 所有实例共享同一份函数
console.log('rendering with', this.data.length);
};
const c1 = new Chart([1,2,3]);
const c2 = new Chart([4,5,6]);
console.log(c1.draw === c2.draw); // true ✅
这样无论创建 10 个还是 1000 个 Chart 实例,draw 方法只占一份内存。
用对象池管理高频创建/销毁的大对象
如果实例本身携带大数组、TypedArray、CanvasPattern 或其他重量级属性(比如 new Float64Array(10000)),频繁 new/delete 会加剧新生代 GC 压力,还可能触发内存碎片。
这时适合引入对象池:
- 预先创建一批对象,使用时
acquire()取出,用完release()归还 - 归还前重置关键字段(如清空数组、置 null 引用),不真正 delete
- 池大小可设上限,防止内存无节制增长
class ArrayPool {
constructor(size) {
this.size = size;
this.pool = [];
}
acquire() {
return this.pool.pop() || new Float64Array(this.size);
}
release(arr) {
arr.fill(0); // 重置内容
if (this.pool.length
警惕闭包捕获大变量导致隐式内存驻留
构造函数内定义的私有函数若引用了本不该长期存在的大数据,就会让整个数据无法被回收:
// ❌ 危险:每个实例的 handler 都闭包捕获了整个 largeData
function Table(largeData) {
this.data = largeData;
this.onClick = function() {
console.log('clicked', largeData.length); // largeData 被绑定住
};
}
// ✅ 改法:只捕获必要字段,或用 WeakMap 存关联
function Table(largeData) {
this.data = largeData;
this.id = Symbol();
tableCache.set(this.id, largeData); // 外部 WeakMap 管理
this.onClick = () => console.log('clicked', tableCache.get(this.id)?.length);
}
尤其注意事件监听器、定时器回调、Promise.then 中的函数——它们很容易无意中延长大数据生命周期。
能用字面量就别 new,能复用就别重建
构造函数里尽量少做“一次性初始化”:
- 避免
new Date()、new RegExp()放在构造函数里(可提成静态常量) - 配置对象用
Object.freeze({})共享,别每次 new Object - 字符串拼接多用模板字面量,少用
new String()或反复+=
这些细节单看微小,但乘以千次实例,就是可观的内存和 GC 开销。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











