Почему объекты не уничтожаются даже после запуска $destroy?

Я сделал директиву, которая при щелчке создает диалоговое окно, которое добавляется к телу с помощью jQuery. Проблема в том, что при закрытии диалога области видимости никогда не очищаются должным образом. Как показано на рисунке ниже 167 ChildScopes сохраняются. Что соответствует количеству элементов в диалоговом окне, которое включает директиву ng-repeat.

enter image description here

Я попытался создать чрезвычайно простую версию сценария на Plnkr. К моему удивлению, области на самом деле удаляются на каждом близком расстоянии в Plnkr. Так что что-то, где-то в производстве, заставляет объекты оставаться в живых даже после того, как был вызван $destroy.

link: ($scope, $element, $attr) ->
  $element.on 'click', () ->
      $scope.$apply () ->
        child = $scope.$new()
        template = """<span ng-controller="ListCtrl">...List dialog things...</span>"""
        compiledTemplate = $compile(template)(child)
        container = containers.createDialogContainer($element)
        container.append(compiledTemplate)

        #cleanup
        $scope.closeWidget = () ->
          container.trigger("container_close")
          return

        container.on "container_close", ()->
          child.$apply () ->
            child.$destroy()
          return

Итак, вот мой вопрос:

Что может привести к тому, что область видимости останется в живых даже после того, как был вызван, вызван и запущен вызов $destroy?

По понятным причинам я не могу показать вам наш производственный код. Однако директива в Plnkr соответствует достаточному отладке.

Ответы

Ответ 1

В общем случае область (или любой другой объект JS) не может быть очищена GC, если она все еще доступна другому объекту JS.

На практике в проекте Angular, который также использует JQuery, это, скорее всего, вызвано:

  • Angular служба, контроллер, область действия или какой-либо другой объект, все еще имеющий ссылку на объект области видимости
  • ссылка на ваш объект все еще существует через элемент DOM, возможно, через прослушиватель событий. Элемент DOM может не быть GC-способным, потому что он все еще находится в кеше JQuery

Например, ваш пример создает утечку памяти.

Из вашего кода:

 $scope.removeDialog = () ->
    console.log "closing"
    child.$destroy()
    $('.listshell').remove()
    return

Вы не устанавливаете child в null, поэтому $scope.removeDialog все еще имеет доступ к объекту области, на который ссылается переменная child. Следовательно, этот объект не может быть GC'ed.

NB: Мне кажется, что было бы более целесообразно поместить removeDialog в область содержимого. Теперь ваш пример работает только потому, что область содержимого не изолирована.

Ответ 2

Функции закрытия могут привести к тому, что объект Activation останется активным даже после того, как область была "уничтожена". Например, у вас могут быть внутренние функции, которые все еще ссылаются на объекты переменных в функциях, объем которых вы пытаетесь уничтожить.

обнуление ссылочных переменных будет лучшим вариантом, а не удалением

Ответ 3

Единственное, что я могу придумать, это то, что если у вас где-то есть глобальная функция или функция вне контроллера или директивы, которая ссылается на метод внутри области действия для директивы, то он будет продолжать поддерживать эту область действия в течение всего времени приложение.