Loren on the Art of MATLAB

July 29th, 2008

Understanding Object Cleanup

Today I would like to introduce a guest blogger, Nick Haddad, a developer here at The Mathworks who works on Audio & Video related features in MATLAB. Today he talks about cleaning up different types of objects in MATLAB.

Contents

Introduction

The other day I was reading a post about sound card spectral analysis from the excellent new iheartmatlab blog. Beyond being a great post on recording from sound cards, the author ran into an issue involving object lifetime that has tripped me up in the past too.

So, today I would like to talk about two types of objects in MATLAB, scoped objects and user-managed objects. Knowing which kind of object you are working with can avoid all sorts of confusion. Let's start with a small example.

Recording Audio With a Callback

Suppose you want to use the audiorecorder object to record some audio from your sound card. The audiorecorder has a property called TimerFcn, which allows you to specify a callback function. This callback function calls a function you specify while you are recording audio. Here's an example function.

function makeRecorder( timerCallback, timerPeriod )

% Create an audio recorder object
recObject = audiorecorder();

% Install a callback is called every 'timerPeriod' seconds
set( recObject, ...
    'TimerFcn', timerCallback, ...
    'TimerPeriod', timerPeriod );

% start recording
record( recObject );

end

Once recording has started, the function timerCallback is called every timerPeriod seconds. This can be handy for inspecting audio data as it is streaming in.

On the face of things the makeRecorder function looks like it is ready to run. But, there is one subtlety that causes this function not to work as expected. When the makeRecorder function ends, the recObject variable goes out of scope, is removed from the workspace, and cleans itself up. For an audiorecorder object, cleaning up means:

  • Stop recording
  • Remove the installed timer callback
  • Remove all audiorecorder data from memory

In this case the timerCallback is never called because when makeRecorder ends, recording immediately stops and the audiorecorder's timer is shut down.

The reason the object is cleaned up is because the lifetime of an audiorecorder object is bound by its scope. To keep the object alive you would need to copy the object's local variable out of the makeRecorder function.

function recObject = makeRecorderBetter( timerCallback, timerPeriod )

% Create an audio recorder object
recObject = audiorecorder();

% Install a callback is called every 'timerPeriod' seconds
set( recObject, ...
    'TimerFcn', timerCallback, ...
    'TimerPeriod', timerPeriod );

% start recording
record( recObject );

end

Now recObject will be in the workspace of the code that calls makeRecorder, which allows the audiorecorder to stay alive.

Scoped Objects vs. User-Managed Objects

The audiorecorder object is what I like to call a scoped object because it cleans up after itself when it goes out of scope. Scoped objects are the most common type of object in MATLAB. They behave just like regular scalar and matrix variables.

% Create and clear a scalar
z = sin(pi);
clear z;

% Create and clear a 3 x 3 matrix
M = magic(3);
clear M;

% Create and clear a timeseries object
t = timeseries();
clear t;

Clearing the timeseries object above removes the timeseries from memory completely, just like clearing a scalar or matrix variable.

The reason the makeRecorder example above can be confusing is that some objects in MATLAB clean themselves up when they go out of scope, and some don't. If you try the same type of thing with a timer object, the results are very different.

function makeTimer( timerCallback )

timerObject = timer('TimerFcn',timerCallback, ...
                    'Period', 0.25, ...
                    'ExecutionMode', 'fixedSpacing' );
start( timerObject );

end

In this example, the variable timerObject goes out of scope at the end of makeTimer, but the timer does not get cleaned up. So, the timer fires every 0.25 seconds and the callback function timerCallback is called appropriately. Let's test it out.

% Create a timer
makeTimer( @(obj, event) display([obj.Name ' fired']) );

% pause for a second to let the timer fire
pause(1);
timer-1 fired
timer-1 fired
timer-1 fired
timer-1 fired

You can see here that the timer fired 4 times in one second, even though I can no longer get to the timer object I created.

Timer objects are what I like to call user-managed objects, in that they don't clean up after themselves. You are responsible for cleaning up a timer by calling the delete method after you are done with the timer.

But, after makeTimer ends, the timerObject variable is no longer in the workspace, so you will need to find it using the timerfind function.

% find all outstanding timers
timers = timerfind();

% stop the timers you find
stop(timers);

% delete and clear the timers
delete(timers);
clear timers;

Why do User-Managed Objects Exist?

Using a user-managed object seems like extra work, but you get flexibility over the object's lifetime expressely because it can remain around regardless of a variable's scope. This can be very helpful in several situations, like when you are building GUIs. For example, you could create a timer object in the CreateFcn of a figure window which refreshes the figure every second, and then clean up the timer in the figure's DeleteFcn.

Also, if you are working with a user-managed object and would like to treat it as a scoped object, you can use onCleanup, which was introduced in R2008a. See Loren's previous post that covers onCleanup, Keeping Things Tidy.

Scoped or User-Managed?

MATLAB has a lot of different user-managed objects including timer, analoginput, and videoinput to name a few. Each of these has a corresponding find function to help you find objects that have been removed from the workspace but are still hanging around in memory.

If you are struggling to figure out if an object is scoped or user-managed, follow these guidelines:

  • Assume the object you are using is a scoped object and will tidy up after itself.
  • If an object's documentation mentions a delete function, it might be a user managed object.
  • If an object's documentation has a xxxfind method (timerfind, daqfind, etc.), it is most likely a user-managed object.

Regardless of the guidelines above, it is good just to know that scoped objects and user-managed objects exist in MATLAB and that there are differences between the behavior of each.

Has this ever happened to you?

Have you ever run into issues with user-managed objects? Has an object in MATLAB ever been cleaned up when you weren't expecting it too? Share you experiences here.


Get the MATLAB code

Published with MATLAB® 7.6

7 Responses to “Understanding Object Cleanup”

  1. StephenLL replied on :

    Great article.

    Is there any documentation or guidelines for building “User-Managed Objects”?

    The only way I can think of building a function like this is using persistent variables.

    Other then GUIs, I can see other situations where these will be convenient such as utilities. a logging utility comes to mind, also an enumerator class.

    Thanks again.
    Stephen

  2. Nick Haddad replied on :

    There aren’t any guidelines per say, but persistent variables would be a great way of keeping some data around if one of your object’s variables goes out of scope.

    You could also create a MATLAB class that implements the Singleton design pattern using static methods and a persistent variable. This would give you a nice interface to some data that stays around in memory, but doesn’t require an object variable at all.

    For more info on singleton see Wikipedia:
    http://en.wikipedia.org/wiki/Singleton_pattern

  3. Loren replied on :

    Stephen-

    If you do use persistent variables, you have to be careful about how multiple instances of the class work. Today you have 2 more choices that don’t limit you to a singleton pattern, nested functions or the object system introduced in R2008a. There will be a blog on the latter coming soon. In the meantime, check out the documentation on the class system.

    –Loren

  4. Gautam Vallabha replied on :

    Another example of user-managed objects are graphics objects (FIGURE, AXES, PATCH, LINE, etc.). Nick’s guidelines work for these as well:
    1) There is a DELETE function for the graphics objects
    2) There is a FINDALL function that can be used to catch all the HG objects, including those with visibility set to ‘off’.

    With regard to Stephen’s question: one guideline for building user-managed objects is to allow the user to assign a unique name to the object. This makes it easy to find them later. For example:

    ———–
    timer(’period’,0.25, ‘name’, ‘myTimer’);

    % much later … in some other function
    h = timerfind(’name’, ‘myTimer’);
    stop(h);
    delete(h);
    ———–

    This strategy works with pretty much all user-managed objects in MATLAB.

  5. StephenLL replied on :

    Nick, Loren, Gautam:

    Thank you for replying and your ideas. I have a lot to learn and experiment with now.

    I don’t plan to make wide spread use of this technique for the obvious pitfalls like hidden dependence, but there is some functionality well served by it.

    Thanks again.

    Stephen

  6. Kieran Parsons replied on :

    I am trying to clean up a singleton GUI object (using a persistent variable as suggested in 2 and http://www.mathworks.com/access/helpdesk/help/techdoc/index.html?/access/helpdesk/help/techdoc/matlab_oop/bru6n2g.html.)

    When the object is created I create a GUI figure window, and I want them to always exist as a pair. I have added a ‘CloseRequestFcn’ callback that closes the figure and deletes the object if a user hits the close button. This works fine. However, I cannot figure out how to get the GUI figure to close if I clear the singleton object. I tried overloading the ‘delete’ method(which normally works) but in the case of the clearing of a persistent object it seems that the ‘delete’ method is not called.

    Any ideas?

    Thanks,
    Kieran

  7. Kieran Parsons replied on :

    The very helpful Mathworks technical support team were able to help me out with #6. Their solution is posted at http://www.mathworks.com/support/solutions/en/data/1-ABQ59D/index.html if anyone is interested. An interesting use of strings in callbacks instead of anonymous functions.

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Jun: I totally can not believe it, Loren. You are really helpful. Thank you so much, MATLAB master!
  • Loren: Wow folks- Always lots of interest when there’s a quickie to try out! I will only make 2 general...
  • Loren: Jun- ismember is your friend here: >> [aa,ind] = ismember(Array2,Arra y1) aa = 1 1 1 1 1 1 1 ind = 1 2 1 4 4 3...
  • Dan: I like the first way better than the second way. Combining the arrays into one and running any is nice, although...
  • James Myatt: How about I = (a == 0 | b == 0); a(I) = []; b(I) = [];
  • Tunc: Hello Loren, love your blog because of such inspiring and challenging comments to such ’small’...
  • Pekka Kumpulainen: Here is my tradeoff. I usually want to keep the original variables as they are most probably...
  • Iain: Followup: Of course, to allow NaNs (counting them as non-zero): mask = (a~=0) & (b~=0); The mask says “a...
  • Matt Fig: I would usually go with something like this: y = a&b; x = a(y); y = b(y); But I was surprised to find...
  • kk: c=all([a;b]) a(c) a(b)

These postings are the author's and don't necessarily represent the opinions of The MathWorks.