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.
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.
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.
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;
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.
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.
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.
Published with MATLAB® 7.6