order of variable deletion and creation

6 views (last 30 days)
Is the order in which the left hand side is deleted and the right hand side executed defined?
i.e.
output = createNewOutput();
If "output" exists, does it get deleted first, before createNewOutput runs? Or alternatively, does createNewOutput run before output is deleted? Is this behavior undefined?
  2 Comments
Jim Hokanson
Jim Hokanson on 25 Jul 2017
Thanks all for the comments. I realized I should probably have done some testing to see if one answer seemed to be most common, suggesting that to be the correct answer or that alternatively the behavior is random but tends to go one way.
I had not considered the approach of an error on the right hand side. My actual use case is communicating with a hardware interface, and running into problems with having two instances of a class connecting to a device. The best approach to fixing this is obviously to insert logic that prevents this, but I was curious as to what type of behavior I should expect. I'll add some print statements to the constructor and to the delete function of the class to observe the behavior, which presumably will show the constructor before the delete call.
The logic of preserving the output in the case of an error during the execution of the right hand side is interesting. Alternatively, I had thought you might want to delete the left hand side to ensure sufficient resources for right hand side execution.
Will update after more testing. Many thanks for the answers.
Jim Hokanson
Jim Hokanson on 25 Jul 2017
As per the suggested answers, the constructor was getting called before the delete method, confirming in this case the right hand side evaluation before clearing the left hand side variable.

Sign in to comment.

Accepted Answer

the cyclist
the cyclist on 24 Jul 2017
Edited: the cyclist on 24 Jul 2017
If I understand you correctly, the output will not be deleted first.
You can easily test this yourself. Create the following function in your workspace:
function output = thisWillCrash()
this will crash
end
Then run the following code in your workspace:
output = 'I exist!';
output = thisWillCrash()
You will see that the original value of output still exists, because the new value was never generated, and never overwrote the old one.
Anticipating that you might have other memory-usage questions, let me refer you to some documentation about how MATLAB allocates memory.
  1 Comment
James Tursa
James Tursa on 24 Jul 2017
Edited: James Tursa on 5 Oct 2018
Some additional notes about the description in that link, since the argument passing behavior differs depending on whether you are calling an m-file (or p-file) or mex routine.
First:
All sub-element references (i.e. from cell or struct arrays) are always evaluated as shared data copies of the original, regardless of the type of function you are calling. With that in mind ...
myFunction(A,C,C{1},S,S.field)
Where A = a numeric, logical, or char variable
C = a cell array
S = a struct array
Then the arguments will be passed as follows:
A
- Shared data copy gets passed to m-file (and p-file)
(except in some cases a scalar variable gets passed as a deep copy)
- The original variable gets passed to mex routines R2015a and earlier
- Shared data copy gets passed to mex routines R2015b and later
C
- Shared data copy gets passed to m-file (and p-file)
- The original variable gets passed to mex routines R2015a and earlier
- Shared data copy gets passed to mex routines R2015b and later
C{1}
- Shared data copy gets passed to m-file (and p-file)
- Shared data copy gets passed to mex routines
S
- Shared data copy gets passed to m-file (and p-file)
- The original variable gets passed to mex routines R2015a and earlier
- Shared data copy gets passed to mex routines R2015b and later
S.field
- Shared data copy gets passed to m-file (and p-file)
- Shared data copy gets passed to mex routines
Then inside myFunction the regular rules apply for changing variables. If the variable is a shared data copy of something else (regardless of whether it came from the input argument list or came from some other calculations) then a deep copy is made first before the changes are applied.
For "in-place" m-file operations, deep data copies are not made if specific syntax rules are followed.
For class variables derived from handle, the behavior is different and doesn't follow the normal shared data copy rules.

Sign in to comment.

More Answers (2)

James Tursa
James Tursa on 24 Jul 2017
Edited: James Tursa on 24 Jul 2017
I don't think this behavior is formally documented. My observations have been that the mxArray structure for "output" is retained, but the internal values of the mxArray get replaced by whatever gets returned by createNewOutput. E.g.,
>> format debug
>> x = 1:3
x =
Structure address = 6effc58
m = 1
n = 3
pr = 2d3ee750
pi = 0
1 2 3
>> x = 4:6
x =
Structure address = 6effc58
m = 1
n = 3
pr = 2d3f4cc0
pi = 0
4 5 6
>> x = single(7:9)
x =
Structure address = 6effc58
m = 1
n = 3
pr = 26f51950
pi = 0
7 8 9
Here you can see that the mxArray struct for "output" lives at 6effc58. And through all of the assignments that doesn't change. But the data pointer pr does change with each new assignment. I would hazard a guess that this is the order in which things take place:
1) createNewOutput executes and creates a new temporary "result"
2) "output" gets turned into a shared data copy of "result"
3) the temporary "result" gets destroyed
So for step 1, my guess is that both data blocks of "output" and "result" exist in memory at the same time, and the original data block of "output" doesn't get free'd until step 2. This seems to be borne out by the following example (but maybe different behavior could occur in different circumstances such as functions operating "in-place" on a variable):
>> n = 500*1024*1024/8
n =
65536000
>> memory
Maximum possible array: 2045 MB (2.144e+009 bytes) *
Memory available for all arrays: 3220 MB (3.376e+009 bytes) **
Memory used by MATLAB: 600 MB (6.294e+008 bytes) <-- start with 600 MB used
Physical Memory (RAM): 32690 MB (3.428e+010 bytes)
* Limited by contiguous virtual address space available.
** Limited by virtual address space available.
>> x = zeros(n,1);
>> memory
Maximum possible array: 1545 MB (1.620e+009 bytes) *
Memory available for all arrays: 2720 MB (2.852e+009 bytes) **
Memory used by MATLAB: 1100 MB (1.154e+009 bytes) <-- Add a 500 MB array
Physical Memory (RAM): 32690 MB (3.428e+010 bytes)
* Limited by contiguous virtual address space available.
** Limited by virtual address space available.
>> x = createNewOutput(n);
Maximum possible array: 1044 MB (1.095e+009 bytes) *
Memory available for all arrays: 2220 MB (2.328e+009 bytes) **
Memory used by MATLAB: 1600 MB (1.678e+009 bytes) <-- another 500 MB inside of function
Physical Memory (RAM): 32690 MB (3.428e+010 bytes)
* Limited by contiguous virtual address space available.
** Limited by virtual address space available.
>> memory
Maximum possible array: 1044 MB (1.095e+009 bytes) *
Memory available for all arrays: 2720 MB (2.852e+009 bytes) **
Memory used by MATLAB: 1100 MB (1.154e+009 bytes) <-- back down to only one 500 MB added block
Physical Memory (RAM): 32690 MB (3.428e+010 bytes)
* Limited by contiguous virtual address space available.
** Limited by virtual address space available.
If you want to force MATLAB to clear the "output" data memory first so two large data blocks will not be in memory at the same time, then you should probably do this prior to calling createNewOutput:
output = [];
That way the mxArray struct is still retained (as MATLAB seems to like to do) but the original data block gets free'd first.

John D'Errico
John D'Errico on 24 Jul 2017
I assume you are asking this if there is a bug in the right hand side. Will MATLAB have already deleted the output variable?
The answer is MATLAB performs the operation on the right hand side, BEFORE it does an assignment, also before the left hand side is replaced. So the right hand side is created before MATLAB worries about where the result will be stuffed.
A simple test of this is:
L = rand(10,1);
L(2:3) = rand(2,2)
In an assignment A(:) = B, the number of elements in A and B must be the same.
L
L =
0.43874
0.38156
0.76552
0.7952
0.18687
0.48976
0.44559
0.64631
0.70936
0.75469
So MATLAB did not think about if the result would even fit into the left hand side, until the RHS existed.
You might argue that might not be a good test of the behavior you are asking about, since MATLAB might do things differently in other cases. But it is equally easy to write a simple function with an error in it.
fun = @(x) x(:,2);
A = ones(10,1);
X = rand(10,1);
A = fun(X)
Index exceeds matrix dimensions.
Error in @(x)x(:,2)
>> A
A =
1
1
1
1
1
1
1
1
1
1
So, A was created as a column vector of all ones. Then create X as a column vector with ONE column, and a function that extracts column 2 of the input. So, if I try to use this function to overwrite A, the function result must fail, BEFORE a result exists. If MATLAB were to delete A first before the function was executed, then A will not exist.
As you can see in the test, A is still the vector of ones it was before I tried to replace it, thus confirming my claim.

Categories

Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange

Tags

Community Treasure Hunt

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

Start Hunting!