我正在开发一个Angular应用程序,我创建了一个这样的下载页面:
如果我查看Chrome任务管理器,我会发现与我的应用程序相关的进程会保留大约130 MB的内存。
然后,用户可以点击每个下载按钮启动同时下载(总文件大小为266 MB):
现在,如果我再次检查任务管理器,我会看到内存使用量增加,所有下载完成后,其峰值大约为650 MB。 我注意到一个奇怪的事情:记忆的最终用法似乎是以下公式的总和:
初始内存使用量+ 2 *总文件大小=最终内存使用量
130 MB + 2 * 266 MB = 130 MB + 532 MB = 662 MB = ~650 MB。
如果我尝试使用Chrome垃圾收集器,它会减少大约30 MB,但我仍然拥有620 MB作为内存使用量的应用程序。
那么,我该如何解决这个问题呢?你能看到我的代码有什么问题吗?
(我尝试在Component的unsubscribe
上使用ngOnDestroy
,但它不起作用)
当我点击文件的下载按钮(从下载页面)时,这是调用的函数:
getFile(file: any): void {
this.fileDownloadService.downloadFile(file).subscribe(
(fileinfo: SispFile) => {
file.downloading = true;
},
(err: any) => {
file.downloading = false;
console.log('errore', err);
},
() => {
file.downloading = false;
console.log('completated');
});
}
以下是downloadFile
中的FileDownloadService
函数,由getFile
调用:
downloadFile(file: SispFile): Observable<any> {
let conf: any = {};
conf.totalChunks = Math.max(Math.ceil(file.size / this.chunkSizeDownload), 1);
conf.mime = file.extension;
conf.currentChunk = 0;
conf.byteDownloaded = 0;
conf.chunkSizeDownload = this.chunkSizeDownload;
conf.chunkBlobs = [];
conf.finalBlob = null;
file.progress = 0;
return new Observable(observer => {
observer.next(file);
this.addChunk(file, observer, conf);
})
}
addChunk(file: SispFile, observer: any, conf: any) {
if (conf.currentChunk == conf.totalChunks) {
observer.complete();
conf.finalBlob = new Blob(conf.chunkBlobs, {type: conf.mime});
let fileURL = URL.createObjectURL(conf.finalBlob);
let a = document.createElement("a");
a.href = fileURL;
a.download = file.name;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(fileURL);
} else {
this.docService.downloadFile(file, conf.chunkSizeDownload, conf.byteDownloaded)
.then(response => {
let typedArray = this.createBlob(response['_body'], conf.mime);
conf.chunkBlobs[conf.currentChunk] = typedArray;
conf.currentChunk++;
conf.byteDownloaded = conf.currentChunk * conf.chunkSizeDownload;
if (conf.Downloaded + this.chunkSizeDownload > file.size) {
conf.chunkSizeDownload = file.size - conf.Downloaded + 1;
}
let progress = Math.round((conf.currentChunk * 100) / conf.totalChunks);
file.progress = progress;
observer.next(file);
this.addChunk(file, observer, conf);
})
.catch((error: ErrorMessage) => {
observer.error(error);
console.log('Errore server: ' + error);
});
}
}
以下是DocService
中对后端端点的最终调用:
downloadFile(file: SispFile, length: number, offset: number) {
let url = Util.format(this.downloadFileUrl, {id: file.id});
let body: any = { "downloadMode": "PAYLOAD", "fileId": file.id, "length": length, "offset": offset };
return this.http.post(url, body)
.toPromise()
.then(response => {
return response;
})
.catch(this.handleError);
}
答案 0 :(得分:1)
我发现Angular有这个Testability
类。它的定义是:
Testability服务提供可以访问的测试挂钩 来自浏览器和Protractor等服务。每个自举 页面上的Angular应用程序将具有Testability的实例。
您可以通过TestabilityRegistry
访问针对特定元素的可测试性实例的全局注册表。
正如我们在this issue中看到的那样,销毁组件并不会释放浏览器的内存,因为Testability API不会释放它的引用。
所以,也许,通过在destroy上清理TestabilityRegistry可以帮助你摆脱那些总结导致你的620MB内存泄漏的引用。
我找到的是the fix!
我希望这有助于解决你的问题,或者至少我希望我能设法给你一个不同的观点或新的研究领域!
<强>更新强>
从我所看到的,为了清理TestabilityRegistry
:
在 modules /@angular/core/src/testability/testability.ts :
destroy(): void {
this._applications.clear();
testabilityGetter.onDestroy();
}
这将是 destroy 方法。
在 modules /@angular/core/src/application_ref.ts :
this._injector.get(TestabilityRegistry).destroy();
我们调用destroy方法。
在 modules /@angular/platform-browser/src/browser/testability.ts :
onDestroy(): void {
delete global.getAngularTestability;
delete global.getAllAngularTestabilities;
delete global.getAllAngularRootElements;
delete global.frameworkStabilizers;
}
在销毁时,我们确保删除可测试性实例。
查看this commit。它向您展示了如何清理TestabilityRegistry。