您现在的位置是:网站首页 > 垃圾回收机制对设计模式的影响文章详情
垃圾回收机制对设计模式的影响
陈川
【
JavaScript
】
21267人已围观
5201字
垃圾回收机制的基本原理
JavaScript的垃圾回收机制主要基于引用计数和标记清除两种算法。引用计数通过跟踪每个对象的引用次数来判断是否回收,而现代浏览器普遍采用的标记清除算法则会从根对象出发,标记所有可达对象,然后清除未被标记的对象。
// 引用计数示例
let obj1 = { name: 'obj1' }; // 引用计数: 1
let obj2 = obj1; // 引用计数: 2
obj1 = null; // 引用计数: 1
obj2 = null; // 引用计数: 0 (可回收)
单例模式的内存管理
单例模式需要特别注意内存泄漏问题。由于单例对象会长期存在于内存中,如果其中包含对大对象的引用,即使这些对象不再需要也不会被回收。
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
this.cache = new Map(); // 可能造成内存泄漏
}
return Singleton.instance;
}
// 应该提供清理方法
clearCache() {
this.cache.clear();
}
}
观察者模式中的引用关系
观察者模式中常见的错误是忘记移除观察者,导致观察者对象无法被回收。特别是在DOM事件监听中,这种现象尤为常见。
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
// 必须提供移除方法
removeObserver(observer) {
const index = this.observers.indexOf(observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}
}
工厂模式与对象池技术
垃圾回收机制促使我们在频繁创建销毁对象时考虑对象池技术。工厂模式可以很好地与对象池结合,减少GC压力。
class ObjectPool {
constructor(createFn) {
this.createFn = createFn;
this.pool = [];
}
acquire() {
return this.pool.length > 0 ? this.pool.pop() : this.createFn();
}
release(obj) {
// 重置对象状态
this.pool.push(obj);
}
}
// 使用示例
const pool = new ObjectPool(() => ({ x: 0, y: 0 }));
const obj = pool.acquire();
// 使用完毕后
pool.release(obj);
装饰器模式与内存泄漏
装饰器模式容易在装饰链中形成长引用链,如果不注意断开引用,可能导致原始对象无法被回收。
function withLogging(fn) {
return function(...args) {
console.log('Calling function');
return fn.apply(this, args);
};
}
// 使用后应该保留原始引用以便取消装饰
const originalFn = someObject.method;
someObject.method = withLogging(originalFn);
// 取消装饰
someObject.method = originalFn;
策略模式中的函数对象
策略模式中频繁创建函数对象可能增加GC负担,可以考虑缓存策略函数或使用原型共享。
const strategies = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
// 避免在每次调用时创建新函数
};
function calculate(strategy, a, b) {
return strategies[strategy](a, b);
}
代理模式与WeakMap
Proxy对象可以拦截各种操作,但要注意代理目标的生命周期。WeakMap可以帮助管理这种关系而不妨碍垃圾回收。
const proxyCache = new WeakMap();
function createProxy(target) {
if (proxyCache.has(target)) {
return proxyCache.get(target);
}
const proxy = new Proxy(target, {
get(target, prop) {
console.log(`Getting ${prop}`);
return target[prop];
}
});
proxyCache.set(target, proxy);
return proxy;
}
命令模式与撤销操作
命令对象通常需要保存状态以实现撤销,这可能导致内存占用增加。可以通过限制历史记录长度或定期清理来解决。
class CommandManager {
constructor(maxHistory = 50) {
this.history = [];
this.maxHistory = maxHistory;
}
execute(command) {
command.execute();
this.history.push(command);
// 防止内存无限增长
if (this.history.length > this.maxHistory) {
this.history.shift();
}
}
}
享元模式的内在状态
享元模式通过共享相同内在状态来减少内存使用,这与垃圾回收机制的目标高度一致。
class FlyweightFactory {
constructor() {
this.flyweights = {};
}
getFlyweight(key) {
if (!this.flyweights[key]) {
this.flyweights[key] = new Flyweight(key);
}
return this.flyweights[key];
}
}
class Flyweight {
constructor(intrinsicState) {
this.intrinsicState = intrinsicState;
}
operation(extrinsicState) {
console.log(`Intrinsic: ${this.intrinsicState}, Extrinsic: ${extrinsicState}`);
}
}
职责链模式中的中间件
在Node.js中间件系统中,职责链模式被广泛使用。需要注意中间件数组的增长可能导致内存问题。
class Middleware {
constructor() {
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
}
// 应该提供移除中间件的方法
remove(fn) {
const index = this.middlewares.indexOf(fn);
if (index > -1) {
this.middlewares.splice(index, 1);
}
}
}
访问者模式与对象遍历
访问者模式在遍历复杂对象结构时,需要注意避免在访问过程中创建大量临时对象。
class Visitor {
visitElement(element) {
// 避免在visit方法中创建新对象
element.process();
}
}
// 使用对象池优化访问者实例
const visitorPool = new ObjectPool(() => new Visitor());
const visitor = visitorPool.acquire();
// 使用后归还
visitorPool.release(visitor);
状态模式中的状态转换
状态模式中状态对象的频繁切换可能增加GC压力,可以通过共享状态对象来优化。
class State {
constructor() {
if (State._instance) {
return State._instance;
}
State._instance = this;
}
}
// 共享状态实例
const state1 = new State();
const state2 = new State();
console.log(state1 === state2); // true
备忘录模式与内存消耗
备忘录模式保存对象状态可能占用大量内存,应该考虑限制快照数量或使用增量存储。
class Originator {
constructor() {
this.state = {};
}
save() {
return new Memento({ ...this.state });
}
restore(memento) {
this.state = { ...memento.getState() };
}
}
class Memento {
constructor(state) {
this.state = state;
}
getState() {
return this.state;
}
}
中介者模式与对象引用
中介者作为通信中心,持有大量组件引用,需要特别注意在组件销毁时从中介者中注销。
class Mediator {
constructor() {
this.components = new Set();
}
register(component) {
this.components.add(component);
component.setMediator(this);
}
// 必须提供注销方法
unregister(component) {
this.components.delete(component);
component.setMediator(null);
}
}
上一篇: 浏览器引擎优化与设计模式选择
下一篇: 频繁操作场景下的模式优化