Найти, где дескриптор хранится в области

Объекты класса управления MATLAB удаляются, когда они выходят за пределы области видимости. У меня есть объекты, которые можно использовать повторно в разных частях приложения, но которые я хочу уничтожить, когда они больше не используются нигде. MATLAB, построенный по жизненному циклу, позволяет мне это делать, не поддерживая какой-либо дополнительный глобальный список, чтобы отслеживать, что может использовать этот объект.

Однако у меня есть ситуация, когда объект, который, как мне кажется, должен был выйти из области действия, по-прежнему вызывает вызовы прослушивателя событий, которые удаляются как часть деструктора объекта. Я знаю, где, по-моему, последний дескриптор этого объекта должен быть сохранен, и, конечно, достаточно, когда я проверю, что этот дескриптор был очищен. Поэтому в этом месте должны быть экземпляры этого дескриптора.

Мое приложение представляет собой сложную сеть объектов, хранящихся как свойства других объектов. Есть ли что-нибудь, что я могу сделать, чтобы помочь отследить, где в области хранения дескриптор этого объекта хранится?

Пример

Сначала настройте класс дескриптора с событием для прослушивания:

classdef Yard < handle
    events
        RollCall
    end
end

Затем класс дескриптора, который реагирует на события RollCall от объекта Yard, отображая некоторый текст, а затем уведомляет о своем собственном событии:

classdef Kennel < handle
    properties
        id
        yardListener
    end

    events
        RollCall
    end

    methods
        function obj = Kennel(yard,id)
            obj.yardListener = event.listener(yard,'RollCall',@obj.Report);
            obj.id = id;
        end

        function Report(obj,~,~)
            fprintf('Kennel %d is in the yard\n', obj.id);
            notify(obj,'RollCall');
        end
    end
end

И, наконец, класс, который реагирует на события RollCall от объекта Kennel, отображая некоторый текст:

classdef Dog
    properties
        name
        kennel
        kennelListener
    end

    methods
        function obj = Dog(name,kennel)
            obj.name = name;
            obj.kennel = kennel;
            obj.kennelListener = event.listener(kennel,'RollCall',@obj.Report);
        end

        function Report(obj,kennel,~)
            fprintf('%s is in kennel %d\n', obj.name, kennel.id);
        end
    end 
end

Теперь добавьте несколько экземпляров этих классов в рабочую область:

Y = Yard;
% Construct two Dog objects, in each case constructing a new Kennel object to pass to the constructor
dogs = [Dog('Fido',Kennel(Y,1)) Dog('Rex',Kennel(Y,2))];
% Construct a third Dog, reusing the Kennel object assigned to dog(1)
dogs(3) = Dog('Rover',dogs(1).kennel);

Теперь у меня есть два объекта Kennel в области видимости, с дескрипторами, указанными в свойствах объектов Dog в массиве dogs. Вызов notify(Y,'RollCall') выводит следующий результат:

Kennel 2 is in the yard
Rex is in kennel 2
Kennel 1 is in the yard
Rover is in kennel 1
Fido is in kennel 1

Если исходные два Dog удалены, то питомник 2 выходит за пределы области действия, но питомник 1 остается активным, так как на него все еще ссылаются остальные Dog:

>> dogs = dogs(3);
>> notify(Y,'RollCall')
Kennel 1 is in the yard
Rover is in kennel 1

Однако, если я скрою дополнительный дескриптор питомника 1 в другом месте в области до удаления оставшегося Dog, он останется активным:

>> t = timer('UserData',dogs(1).kennel);
>> clear dogs
>> notify(Y,'RollCall')
Kennel 1 is in the yard

Вопрос в том, не знаю, где и когда эта дополнительная ссылка была создана и почему она не была удалена, что я могу сделать, чтобы отладить существование объекта?

Ответ 1

Это то, о чем я много говорил. Вы видите, что очистка переменной объекта дескриптора в одной области не приведет к деструктору, если есть еще ссылка на объект в любой другой области. Если вы явно вызвали деструктор объектов Dog и Kennel, ваш объект таймера имел бы ссылку на недопустимый объект.

В конструкторе для Dog создан создатель событий, деструктор которого никогда не вызывается, который сохраняет ссылку на экземпляр Dog.

Я бы выполнил функцию удаления для Dog и Kennel, которая вызывала функция удаления для слушателей. Вот шаблон кодирования, который я использую много.

classdef MyClass < handle
   properties 
      listener % listeners are themselves handle objects
   end
   methods
      %% Class constructor creates a listener 
      %% Class methods
      function delete(obj)
         % do this for all handle object properties
         % Also, avoid calling constructors for handle objects in
         % the properties block. That can create references to handle
         % objects which can only be cleared by a restart
         if ishandle(obj.listener)
            delete(obj.listener)
         end
      end
   end
end

В примере, который вы указали, вы создали объект timer, который также поддерживает ссылку на ваш объект dogs. Очистка dogs не устраняет эту ссылку. Не будет очищать объект timer. Вы должны явно удалить объекты timer.

Я много использую объекты handle и обычно проектирую GUI s to go with them (aside, never, never, never use GUIDE for this. It is the worst thing ever). You have to be sure to clear all references to any дескриптор objects called in your code. I do this by setting the 'DeleteFcn`` для объекта дескриптора графики, который содержит графический интерфейс (может быть фигурой, uicontainer, uipanel и т.д.)., Я включаю этот пример, потому что он иллюстрирует, как необходимо поддерживать ссылки на объекты обработки.

Функция dispGUI (handleOBJ, hg)

  %% build gui in hg
  set(hg,'DeleteFcn',@deleteCallBack)
  h  = uicontrol(hg,'Callback',@myCallback)
  function myCallback(h,varargin)
     % So now there is a reference to handleOBJ
     % It will persist forever, even if cleared in the caller's
     % workspace, thus we clear it when the containing graphics 
     % object delete callback is triggered.
     if isvalid(handleOBJ)
        set(h,'string','valid')
     else
        set(h,'string','invalid')
     end
  end


  function deleteCallBack(varargin)
     % calling clear on handleOBJ clears it from the scope of the 
     % GUI function
     % also call clear on the containing function
     clear handleOBJ
     clear(mfilename)
  end

конец

Другая проблема, которую я заметил с объектами класса handle, заключается в том, что если вы изменяете и сохраняете их файл classdef, пока есть живые ссылки на эти объекты, вы можете иногда попасть в ситуацию, когда есть ссылки на объект, который вы можете только очистить, сбросив Matlab.