Object destructor not running when listeners are involved

2 views (last 30 days)
I have two classes, Plant and Generator. Generator creates a vector and broadcasts it via notify(), which Plant listens for. The classdefs are below. Note that I didn't include the actual data-generation method because it's irrelevent to my question.
classdef Plant < handle
properties
Listener
end
methods
function ListenerCallback(obj, data)
% Perform an operation on data
end
end
end
classdef Generator < handle
properties
plant
end
events
newSignal
end
methods
function obj = Generator(plant)
obj.plant = plant;
obj.plant.Listener = addlistener(obj, 'newSignal', ...
@(src, data) obj.plant.ListenerCallback(data));
end
function delete(obj)
delete(obj.plant.Listener);
disp('Generator instance deleted');
end
end
end
I noticed that the Generator destructor behaves really oddly: the first time I create then delete a Generator instance, it does not run the destructor until the second time I create the Generator instance. Here's an example:
>> P = Plant
P =
Plant handle
Properties:
Listener: []
Methods, Events, Superclasses
>> G = Generator(P)
G =
Generator handle
Properties:
plant: [1x1 Plant]
Methods, Events, Superclasses
>> clear G % DESTRUCTOR NOT DELETED??
>> G = Generator(P)
Generator instance deleted % why is the destructor run now?
G =
Generator handle
Properties:
plant: [1x1 Plant]
Methods, Events, Superclasses
>> clear G
Generator instance deleted % and why is the destructor run properly now?
It's pretty important that my destructor runs every time. What is going on here, and how can I get the destructor to operate properly? (I might just remove the listener altogether and directly call Plant.ListenerCallback() from the Generator instance if this doesn't work out.)

Accepted Answer

Daniel Shub
Daniel Shub on 5 Mar 2012
You are getting caught up in the undocumented and proprietary aspects of MATLAB garbage collection. The thing to note is that the "clear" function does not automatically invoke the "delete" method. The delete method is invoked when there are no more references to an object. Exactly when the delete method is invoke following the removal of the last reference is undocumented. From your example it is clear it is not immediate but waits for something (e.g., the event queue to be flushed). I would not try and figure out the exact behavior and code against it, since it potentially could change.
Your code (with slight modification of G0 and G1:
G0 = Generator(P);
At this point there are two references to G0. The obvious reference in the workspace and a hidden reference in the listener object held in the Listener property of the Plant object.
clear G0 % DESTRUCTOR NOT DELETED??
This removes the reference in the workspace, but not the hidden reference. Since there is still one reference left, the delete method is not invoked.
G1 = Generator(P);
This causes the hidden reference to G0 to be removed when the Listener property of the Plant object is overwritten. It then creates 2 references to G1 (workspace and hidden listener).
The key issue is that at some point after the hidden reference to G1 is created, the delete method to G0 is called. The delete method for G0 removes the hidden reference to G1. Therefore, there is only a single reference to G1 (workspace).
clear G1
This clears the workspace (and only) reference to G1, so the delete method is invoked.
The only way you could get different behavior was if MATLAB prior to assigning G1 to the Listener property of the Plant object, first removed the G0 reference and performed garbage collection (and hence invoked the delete method). It is not clear if this is better or worse (I am guessing worse).
It is hard to recommend a work around without understanding your motivation better.

More Answers (0)

Categories

Find more on Construct and Work with Object Arrays in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!