Angular:并发下载后的内存泄漏?

时间:2017-05-18 11:01:46

标签: angular memory-leaks download observable

我正在开发一个Angular应用程序,我创建了一个这样的下载页面:

enter image description here

如果我查看Chrome任务管理器,我会发现与我的应用程序相关的进程会保留大约130 MB的内存。

然后,用户可以点击每个下载按钮启动同时下载(总文件大小为266 MB):

enter image description here

现在,如果我再次检查任务管理器,我会看到内存使用量增加,所有下载完成后,其峰值大约为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);
}

1 个答案:

答案 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-b​​rowser/src/browser/testability.ts

onDestroy(): void {
   delete global.getAngularTestability;
   delete global.getAllAngularTestabilities;
   delete global.getAllAngularRootElements;
   delete global.frameworkStabilizers;
}

在销毁时,我们确保删除可测试性实例。

查看this commit它向您展示了如何清理TestabilityRegistry。