Нужно ли мне отписываться от Observable, если Observable закончен? - PullRequest
1 голос
/ 08 января 2020

Допустим, у меня есть 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?

Мой логин c говорит мне, что я не знаю, потому что оба Subject Subscription теперь имеют право на сборку мусора и будут уничтожены, даже если они ссылаются друг на друга. Или есть какая-то скрытая ссылка, о которой я не знаю?

Не беспокойтесь о разнице между использованием unsubscribe, takeUntil или другими механизмами.

Ответы [ 2 ]

1 голос
/ 09 января 2020

В случае 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 в вашей консоли, затем скопируйте и вставьте пример кода. Вы заметите увеличение памяти в диспетчере задач. Создавая дамп кучи на вкладке «Память» в инструментах разработчика, вы сможете найти 4 объекта, введя BigClass в поле поиска.

После этого введите subject = null; в консоли , а затем создайте новый дамп кучи. Вы заметите, что 4 объекта исчезли.

В заключение, пока Observable уничтожен, это не реальный риск утечки памяти, поскольку все подписки также будут уничтожены. Рискованными Observables являются те, которые являются постоянными (например: присоединены к глобальному событию DOM с fromEvent) и с обратными вызовами, ссылающимися на объекты, которые должны быть уничтожены.

0 голосов
/ 17 апреля 2020

Для использования памяти нет никакой разницы

Когда вы звоните sub.unsubscribe();, единственное, что Angular делает, это устанавливает наблюдателей на null, , здесь вы можете увидеть код отписки :

  unsubscribe() {
    this.isStopped = true;
    this.closed = true;
    this.observers = null!;
  }

Флаги используются только для дальнейших проверок.

Однако я бы рекомендовал вам придерживаться пути unsubscribe, потому что вы никогда знать что RX JS добавит в будущих версиях. Например, есть вероятность, что они добавляют новую функцию, что-то вроде этого:

  unsubscribe() {
    this.isStopped = true;
    this.closed = true;
    this.observers = null!;
    if (this.coolNewFeature) {
        this.coolNewFeature.unsubscribe()
    }
  }

В этом сценарии ваш подход просто сделать subject = null; вызовет утечки памяти.

...