clear is solwer than writing

1 view (last 30 days)
I have some code generating a large number of large arrays with a runtime of about 4 minutes (including a parfor loop). Memory consumption after completion is about 13 GB. However, when I run clear afterwards, it seems to take forever, so long that I've never actually waited it out (the longest time I've waited is twice the run time before exiting Matlab). How can that be? After all, during creation addresses and variables have to be written, whereas clearing only requires discarding the addresses. Seems a bit weird to me. If I just close Matlab, the workspace is "cleared" in a moment's notice.
Edit: I can't help thinking it must be some kind of bug. If i reduce the number of arrays by a factor of 10, clear takes just a few seconds (and is faster than the writing operation as one would expect).

Accepted Answer

Walter Roberson
Walter Roberson on 20 Oct 2021
My suspicion is that when you use clear for variables that are not "large", that MATLAB takes the time to try to return the memory to the free list in some kind of "best" order. It is known that "large" variables are handled differently: there is a free pool for small variables, and beyond a certain size, MATLAB requests an allocation of free space and returns the memory to the operating system afterwards.
What I do not know at the moment is why returning memory due to reaching the end of a function could that much faster than returning an individual variable.
I know that some implementations of some programming languages use the strategy of allocating a virtual memory heap for all local variables, and returning from the function can consist of deallocating the entire heap in one go, whereas clearing an individual variable could require maintaining a local free list -- more overhead. I do not know whether MATLAB does this; I have never heard that it does, and it has some implementation consequences that I have not seen evidence of. In particular, if you want to return a variable that might have portions allocated locally, then either you do a deep copy out of the local space, or else you have to do some kind of tracking of variables that are marked as return variables, and do a deep copy at the time one of them is assigned to, or else you have to do some kind of tracking of variables that are marked as return variables and do some crufty back tracking to find all places where memory might be returned (including through layers of struct) and allocate those in a different way (that last one seems unlikely.)
Walter Roberson
Walter Roberson on 5 Nov 2021
I do not have access to any information about the implementation of clearing an individual variable.
I decided to attempt some timing tests, to compare item-by-item deallocation to clearing the entire variable. I decided to start with cell arrays, thinking that could help me determine whether deallocation speeds vary depending on variable size.
Anyhow, I implemented two deallocation strategies: clear each cell entry + clear cell, vs just clear the cell.
The timings I got back were quite variable.
I timed the allocations separately, even though the allocations are the same for the two tests. In some initial runs, I was getting allocation times twice as large for the first test than for the second test... implying that first-run might have very different timing characteristics. That's when I switched to repeating each test multiple times.
In the below outputs, column 1 is the allocation times, and "should" be the same for each run, except perhaps for an interation to "warm up". The allocation times in my testing varied a lot more than the run below -- the system is busy right now so the timings are quite different now. But you can see that the allocation times vary by over 50% at times... which should lead us to be suspect about whether the remaining times are meaningful.
Column 2 is the time to deallocate using item-at-a-time strategy. It is 0 for the runs in which individual items are not deallocated.
Column 3 is the time to clear the variable. This is expected to be small-ish for deallocating the cell that was already emptied out, and is expected to be "close to" the second column for the first kind of test.
Column 3 is the total of column 2 and column 3, and so represents the total deallocation times.
It would be a reasonable hypothesis that "maybe" there is some efficiencies available by deallocating the whole cell at once -- at the very least, that less MATLAB-level code would be involved. So it would be quite reasonable for the 4th column of the second test to be less than the 4th column of the first test.
Is that the case though? Answer: Maybe?? In my testing, the mean time for the second test was consistently less than the mean time for the first test, but not by much, and the maximum time for the second test exceeds the mininum time for the first test, so the evidence is weak, at least timing on this online facility. The times on your own system could be rather different...
This is all a big Maybe Pie at the moment. Re-testing would have to be done when the system is less busy.
And meantime I will think about how to test for times spent clearing variables instead of cell entries.
%function driver
format long g
N = 50;
S = 5e5;
MR = 5;
times1 = zeros(MR,4);
times2 = zeros(MR,4);
for R = 1 : MR
T = tic;
C = cell(N,1);
for K = 1 : N
C{K} = ones(1,S);
times1(R,1) = toc(T);
T = tic;
for K = 1 : N
C{K} = [];
times1(R,2) = toc(T);
T = tic;
clear C;
times1(R,3) = toc(T);
T = tic;
C = cell(N,1);
for K = 1 : N
C{K} = ones(1,S);
times2(R,1) = toc(T);
times2(R,2) = 0;
T = tic;
clear C;
times2(R,3) = toc(T);
times1(:,4) = sum(times1(:,2:3),2);
times2(:,4) = sum(times2(:,2:3),2);
times1 = 5×4
0.1063 0.0095 0.0005 0.0100 0.2104 0.0097 0.0001 0.0098 0.1074 0.0091 0.0001 0.0092 0.1107 0.0092 0.0001 0.0093 0.1051 0.0094 0.0002 0.0096
times2 = 5×4
0.1167 0 0.0091 0.0091 0.1144 0 0.0095 0.0095 0.1060 0 0.0093 0.0093 0.1056 0 0.0090 0.0090 0.1053 0 0.0093 0.0093
fprintf('#1 min; max; mean\n');
#1 min; max; mean
[min(times1,[],1); max(times1,[],1); mean(times1,1)]
ans = 3×4
0.1051 0.0091 0.0001 0.0092 0.2104 0.0097 0.0005 0.0100 0.1280 0.0094 0.0002 0.0096
fprintf('#2 min; max; mean\n');
#2 min; max; mean
[min(times2,[],1); max(times2,[],1); mean(times2,1)]
ans = 3×4
0.1053 0 0.0090 0.0090 0.1167 0 0.0095 0.0095 0.1096 0 0.0092 0.0092

Sign in to comment.

More Answers (0)




Community Treasure Hunt

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

Start Hunting!