如果 Observable 完成,我是否需要取消订阅 Observable?
Do I need to unsubscribe from an Observable if the Observable is finished with?
假设我有一个 Observable
(热门,未完成),并且我订阅了它。通常当我完成 Subscription
我必须取消订阅以防止内存泄漏。
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
的引用就足够了,之后所有内容都会被垃圾收集。
当您订阅 object 中的 Subject
并且在清除所有引用之前不取消订阅 Subject
时,内存泄漏的风险变得真实在 object 上。在这种情况下,整个 object 将保持活动状态并且不会被垃圾回收。
让我们举个例子:
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
活动的引用链,并且它将符合垃圾 collection.
要自己观察行为,您可以在控制台中复制此文件的内容https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js,然后复制粘贴示例代码。您会注意到任务管理器中的内存增加。在开发人员工具的“内存”选项卡中创建堆转储时,您可以通过在搜索字段中键入 BigClass
来找到 4 object。
之后,在控制台输入subject = null;
,然后创建一个新的堆转储。您会注意到 4 object 已经消失了。
总而言之,只要 Observable
被销毁,就没有真正的内存泄漏风险,因为所有订阅也将被销毁。有风险的 Observables
是那些永久性的(例如:附加到具有 fromEvent
的全局 DOM 事件),并且回调引用需要销毁的 objects。
不,你不需要
内存使用没有区别。
当你调用 sub.unsubscribe();
时,RXJS 唯一做的就是将观察者设置为 null
,here you can see the original RXJS unsubscribe code:
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null!;
}
标志仅用于进一步验证。
但是我建议您坚持使用 unsubscribe
方式,那是因为 您永远不知道 RXJS 会在未来的版本中添加什么。例如,他们有可能添加新功能,如下所示:
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null!;
if (this.coolNewFeature) {
this.coolNewFeature.unsubscribe()
}
}
在那种情况下,你只是做 subject = null;
的方法会导致内存泄漏(因为 coolNewFeature
可能在其他地方有引用)。
假设我有一个 Observable
(热门,未完成),并且我订阅了它。通常当我完成 Subscription
我必须取消订阅以防止内存泄漏。
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
的引用就足够了,之后所有内容都会被垃圾收集。
当您订阅 object 中的 Subject
并且在清除所有引用之前不取消订阅 Subject
时,内存泄漏的风险变得真实在 object 上。在这种情况下,整个 object 将保持活动状态并且不会被垃圾回收。
让我们举个例子:
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
活动的引用链,并且它将符合垃圾 collection.
要自己观察行为,您可以在控制台中复制此文件的内容https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js,然后复制粘贴示例代码。您会注意到任务管理器中的内存增加。在开发人员工具的“内存”选项卡中创建堆转储时,您可以通过在搜索字段中键入 BigClass
来找到 4 object。
之后,在控制台输入subject = null;
,然后创建一个新的堆转储。您会注意到 4 object 已经消失了。
总而言之,只要 Observable
被销毁,就没有真正的内存泄漏风险,因为所有订阅也将被销毁。有风险的 Observables
是那些永久性的(例如:附加到具有 fromEvent
的全局 DOM 事件),并且回调引用需要销毁的 objects。
不,你不需要
内存使用没有区别。
当你调用 sub.unsubscribe();
时,RXJS 唯一做的就是将观察者设置为 null
,here you can see the original RXJS unsubscribe code:
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null!;
}
标志仅用于进一步验证。
但是我建议您坚持使用 unsubscribe
方式,那是因为 您永远不知道 RXJS 会在未来的版本中添加什么。例如,他们有可能添加新功能,如下所示:
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null!;
if (this.coolNewFeature) {
this.coolNewFeature.unsubscribe()
}
}
在那种情况下,你只是做 subject = null;
的方法会导致内存泄漏(因为 coolNewFeature
可能在其他地方有引用)。