Angular Store内存持续增长:旧状态未释放引发异常
Angular NgRx Store 内存未释放问题排查
我在测试Angular应用时发现异常行为:每次用新数组覆盖Store中的数据,旧状态似乎仍驻留在内存中(仅最新的条形图应为蓝色)。
测试触发代码
为测试,我每5秒分发10次加载动作:
ngOnInit() { setInterval(() => { for (let i = 0; i < 10; i++) { this.store.dispatch(CharacterActions.getCharacters()); } }, 5000); }
Store 定义
export interface CharacterState { characters: Character[]; } export const initialState: CharacterState = { characters: [], }; export const characterReducer = createReducer( initialState, on(CharacterActions.getCharactersSuccess, (state, { characters }) => ({ ...state, characters: [...characters], })) );
Character 类定义
import { Weapon } from "./weapon"; export class Character { name: string; surname: string; private weapons: Weapon[]; constructor(name: string, surname: string, weapons?: Weapon[]) { this.weapons = weapons ?? []; this.name = name; this.surname = surname; } public getWeapons(): Weapon[] { return this.weapons; } public addWeapon(weapon: Weapon): void { this.weapons.push(weapon); } public upgradeWeapon(name: string, value: number) { this.weapons.find(x => x.name === name.toLowerCase())?.upgrade(value); } }
内存未释放的可能原因
- 引用未彻底切断:虽然reducer里用
[...characters]创建了新数组,但如果Character实例或其内部weapons数组被外部组件/服务持有引用,垃圾回收器无法回收旧数据。比如组件订阅Store后未取消订阅,或某处缓存了旧Character对象。 - NgRx DevTools 保留历史:若开启NgRx DevTools,它默认保留所有状态历史用于调试,会导致旧状态被持有无法回收。可检查
StoreModule.forRoot中的maxAge配置,限制历史状态数量。 - Character类的引用泄漏:
getWeapons()直接返回内部数组引用,外部代码若持有该引用,会导致对应Character实例无法被回收。应返回数组副本:return [...this.weapons];。 - 未清理的定时器:
setInterval创建的定时器若未在组件销毁时清除,会持续触发动作,且回调持有组件实例引用,导致组件及相关Store数据无法回收。需在ngOnDestroy中调用clearInterval清理。 - 异步订阅泄漏:
getCharacters()对应的Effect若有未取消的HTTP订阅,或订阅Store时未用takeUntil、async管道自动取消,会导致旧订阅持有状态引用。
内容的提问来源于stack exchange,提问作者Groomer
相关产品推荐
相关产品推荐

