MATLAB: Incorrect memory copy when using property size validator

bugclassMATLABoopproperty validator

When using a size validator in a property block of a class an assigned variable's memory is copied instead of just pointing to it. This is 1) not expected due to standard matlab behavior, and 2) does not happen if using a manual set.prop(this, in) method to do the validation check.
There is then a secondary bug that when assigning a gpu variable and memory runs out (due to this memory bug) instead of giving an out of memory error, I instead get a size validation check did not pass error.
I see the same error on 2019b on a different computer. Example code below:
classdef TestClass < handle
properties
prop (1, :) % also happens with hard coded sizes and n-dimensional arrays
end
end
g = gpuDevice; g.AvailableMemory
ans =
5.2493e+09
>> a = ones(1, 3e8, 'single', 'gpuArray');
g = gpuDevice; g.AvailableMemory
ans =
4.0493e+09 % 1.2GB hit as expected
>> obj = TestClass;
>> obj.prop = a;
>> g = gpuDevice; g.AvailableMemory
ans =
2.8493e+09 % another 1.2GB hit, not expected

Best Answer

I was able to reproduce this in R2018b but not in R2019a or R2019b. It looks like property validators used to trigger a deep copy but that has been fixed. My guess is this is because of the introduction of a gpuArray overload for validateattributes.
Even in R2018b the memory is not lost, it is just not shared. A shared copy is a fragile optimisation that is broken as soon as you edit one of the copies. So in R2019b:
>> clear all
>> gpu = gpuDevice;
>> gpu.AvailableMemory
ans =
1.5565e+09
>> a = ones(1,1e8,'single','gpuArray');
>> gpu.AvailableMemory
ans =
1.1572e+09
>> obj = TestClass;
>> obj.Prop = a;
>> gpu.AvailableMemory
ans =
1.1580e+09
>> a(1) = 0; % Editing one of the variables breaks the shared copy
>> gpu.AvailableMemory
ans =
756809728
Similarly, if you clear a in R2018b you'll gain back the memory you thought you lost:
>> gpu.AvailableMemory
ans =
1.0536e+10
>> a = ones(1,1e8,'single','gpuArray');
>> gpu.AvailableMemory
ans =
1.0135e+10
>> obj = TestClass;
>> obj.Prop = a;
>> gpu.AvailableMemory
ans =
9.7346e+09
>> clear a; % Clearing the original variable gives you back the memory
>> gpu.AvailableMemory
ans =
1.0135e+10
You may have thought that by creating a handle class you were opting into some other kind of sharing behaviour, but that is only about sharing the properties within instances of TestClass.
Related Question