我有一个非常复杂的角度应用程序,它会导致浏览器很快崩溃。所以我正在寻求优化它。我修复了每个订阅内存泄漏,但问题仍然存在。所以我使用Chrome调试模块来尝试找出问题所在。在“内存”选项卡中,我进行记录会话以查找出了什么问题。首先我只激活一些需要理解的东西。
我有一个永远不会破坏的组件,每次点击菜单都会调用refreshWrapper()函数:
refreshWrapper() {
// RESET
this.appS.structure.reset(this.type, this.wrapper, this.appS.navigationS.navigations[this.type + '.' + this.wrapper].step);
// GET GRID
this.appS.restS.post('grid/elements', { route: this.route }).subscribe(response => {
this.appS.structure.displayeds[this.type + '.' + this.wrapper] = new SiteModule(response.displayed);
});
}
这是我的结构模型重置函数,我尝试清除变量:
reset(type: string, wrapper: string, step: string) {
delete this.displayeds[type + '.' + wrapper];
}
查看我的 SiteModule 类构造函数:
constructor(datas ?) {
Object.assign(this, datas);
// GRIDS
if (datas?.grids) {
this.grids = [];
datas.grids.forEach(grid => {
this.grids.push(new Grid(grid));
});
}
}
在网格类中
constructor(datas ?, element ?: Element) {
Object.assign(this, datas);
// BLOCS
if (datas?.blocs) {
this.blocs = [];
datas.blocs.forEach(bloc => {
this.blocs.push(new GridBloc(bloc, element));
});
}
}
GridBloc 类
constructor(datas ?, element ?: Element) {
Object.assign(this, datas);
// ELEMENTS
if (datas?.elements) {
this.elements = [];
datas.elements.forEach(e => {
this.elements.push(new Element(e, element));
});
}
}
元素类
constructor(datas ?, element ?: Element) {
Object.assign(this, datas);
// DETAILS
if (datas?.details) {
this.details = [];
datas.details.forEach(detail => {
this.details.push(new Detail(detail, this.ressource_id));
});
}
}
在 Chrome 内存选项卡中,我看到只有一个 SiteModule 对象。但它保留链接的对象,即我有很多元素对象(即使当我单击菜单时,它也会保留旧的对象,因此当调用refreshWrapper函数时)。
这里有一个内存选项卡屏幕,显示 Element Class(第一个引用 element.model.ts:61 的是好的),但所有其他都是旧的。旧的“[10] dans (GC root) @3”是什么意思?
我不明白为什么。我认为这是垃圾收集器问题,因为我没有销毁组件,并且我将变量存储在全局服务(此处为 AppS)中,但如何解决这个问题?有什么想法吗?
我修复了每个订阅内存泄漏,但问题仍然存在。
在给定的代码中已经存在可见的内存泄漏。
// GET GRID
this.appS.restS.post('grid/elements', { route: this.route })
.subscribe(response => {
this.appS.structure.displayeds[this.type + '.' + this.wrapper] = new SiteModule(response.displayed);
});
这是一次订阅,无法取消订阅。我不知道您的
refreshWrapper
函数被调用的频率,但每次调用都会在您的内存中添加一个订阅。
作为解决方案,我建议使用管道
first
或 take(1)
运算符。
// GET GRID
this.appS.restS.post('grid/elements', { route: this.route })
.pipe(
first(),
).subscribe(response => {
this.appS.structure.displayeds[this.type + '.' + this.wrapper] = new SiteModule(response.displayed);
});