如何在 Angular 应用程序中检测与 rxjs 相关的内存泄漏

Posted

技术标签:

【中文标题】如何在 Angular 应用程序中检测与 rxjs 相关的内存泄漏【英文标题】:How to detect rxjs related memory leaks in Angular apps 【发布时间】:2019-07-06 14:28:59 【问题描述】:

是否有任何工具或技术来检测“遗留”或“当前存在”的可观察对象、订阅。

最近刚刚发现了一个非常严重的内存泄漏,其中组件由于缺少“取消订阅”调用而保持活动状态。我读到了“takeUntil”方法,这似乎很不错。 https://***.com/a/41177163/2050306

但是我仍然想知道是否有任何工具(浏览器扩展等)。据我所知,Augury 并没有覆盖这个区域。

非常感谢所有输入。

【问题讨论】:

这是一个很好的问题。我想这种方法是将其视为 e2e 测试场景并通过传递存根subscribe(),然后在存根中监视订阅。 observable 上有一个标志,表示“关闭”,这将涵盖已完成的订阅,因此不需要显式取消订阅。 @ischenkodv 您的编辑有问题 - Augury 是 robert 所指的工具。请恢复。 @HiramK.Hackenbacker 是的,是的扩展。那个 e2e 测试场景很有趣,你有什么工作代码吗? @HiramK.Hackenbacker 抱歉,已恢复。 看看这个库:github.com/acutmore/leaks/blob/master/leaks.js 【参考方案1】:

免责声明:我是下面提到的工具的作者。

这可以通过保留一个添加新订阅的列表来完成,并在取消订阅后从该列表中删除订阅。

麻烦的部分是观察订阅。实现此目的的一种直接方法是通过猴子修补Observable#subscribe() 方法,即替换 Observable 原型方法。

这是observable-profiler 的整体方法,它是一种开发工具,可连接到 Observable 库(即 rxjs)并在控制台中打印泄漏的订阅。

使用分析器的一种简单方法是在应用启动后开始跟踪,然后在一段时间后停止跟踪:

import  platformBrowserDynamic  from '@angular/platform-browser-dynamic';
import  Observable  from 'rxjs';
import  setup, track, printSubscribers  from 'observable-profiler';

setup(Observable);
platformBrowserDynamic([])
    .bootstrapModule(AppModule)
    .then(ref => 
        track();
        window.stopProfiler = () => 
            ref.destroy();
            const subscribers = track(false);
            printSubscribers(
                subscribers,
            );
        
    );

如果您需要报告,只需在 devtools 控制台中调用 stopProfiler()

【讨论】:

谢谢。这看起来真的很有希望。很快就会回来提供我的发现。 感谢@robert 的反馈! @AndréWerlang 您的工具在使用带有 takeUntil(...) 的管道进行退订时是否正常工作?我使用了你的工具,但 Angular Material 组件出现了很多错误。 @AndréWerlang 并且它不适用于使用管道关闭的流(take(1) / first()),它们被认为没有被您的工具关闭 @Spikolynn 请使用 GitHub 的问题跟踪器报告问题。另外,添加一个重现。

以上是关于如何在 Angular 应用程序中检测与 rxjs 相关的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 6 中使用 rxjs 可观察对象的目的是啥?与 async/await 相比,rxjs 的优势是啥? [复制]

rxjs 与 systemjs 捆绑用于 Angular 2.0 应用程序

如何使用 systemjs 在最小的 Angular 2 应用程序中加载 RxJS?

如何在 Angular/RxJS 中合并两个 observable?

Angular 入门教程系列 34 Angular6下的Http模块与Rxjs6

Angular + RxJS:使用 takeUntil 与简单取消订阅?