假设我有一个 Observable
(热门,未完成),并且我订阅了它。通常,当我完成 订阅
时,我必须取消订阅以防止内存泄漏。
let subject$ = new Subject();
const sub = subject$.subscribe(...);
...
// Need to call sub.unsubscribe() when we are finished
sub.unsubscribe();
sub = null;
但是,如果我不仅完成了 Subscription
,还完成了 Observable
(Subject
),并且删除了所有对两者,我是否需要调用 unsubscribe
方法?
let subject$ = new Subject();
const sub = subject$.subscribe(...);
...
sub = null;
subject$=null;
// Assume I have no other references to these
// Do I need to call sub.unsubscribe() in this case?
我的逻辑告诉我我没有,因为 Subject
和 Subscription
现在都符合垃圾收集的条件,并且将被销毁,即使它们引用了每个其他。还是有一些我不知道的隐藏引用?
不要担心使用unsubscribe
、takeUntil
或其他机制之间的区别。
最佳答案
如果是 let subject$ = new Subject();
清除对 Subject
的引用和 Subscription
就足够了,之后一切都会被垃圾收集。
当您订阅 Subject
时,内存泄漏的风险变得真实。在对象中,并且您不取消订阅 Subject
在清除对象上的所有引用之前。在这种情况下,整个对象将保持事件状态并且不会被垃圾回收。
让我们举个例子:
class BigClass {
constructor(observable) {
this.bigArray = new Array(9999999).fill(0);
observable.subscribe(x => this.result = x);
}
//...
}
let subject = new rxjs.Subject();
let bigObject = new BigClass(subject);
let bigObject1 = new BigClass(subject);
let bigObject2 = new BigClass(subject);
let bigObject3 = new BigClass(subject);
bigObject = null;
bigObject1 = null;
bigObject2 = null;
bigObject3 = null;
在本例中,当清除所有对 bigObject
的引用时, subject
仍然有关于 x => this.result = x
的引用对 bigObject
有引用的回调, 使其整体无法收藏。
通过取消订阅或清除 subject
, 这将打破保持 bigObject
的引用链活着,它将有资格进行垃圾收集。
要自己观察行为,可以复制这个文件的内容https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js在您的控制台中,然后复制粘贴示例代码。您会注意到任务管理器中的内存增加。在开发人员工具的“内存”选项卡中创建堆转储时,您可以通过键入 BigClass
找到这 4 个对象。在搜索字段中。
之后,输入 subject = null;
在控制台中,然后创建一个新的堆转储。您会注意到这 4 个对象已经消失。
作为结论,只要一个Observable
被销毁时,这些并没有真正的内存泄漏风险,因为所有订阅也将被销毁。冒险Observables
那些是永久性的(例如:附加到带有 fromEvent
的全局 DOM 事件),并且回调指向需要销毁的对象。
关于javascript - 如果 Observable 完成,我是否需要取消订阅 Observable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59653696/