在Matlab中截取大数组的有效方法
我在Matlab中有一个大的(多GB)数组,我想截断¹。 天真地说,我认为截断不需要太多记忆,但后来我意识到它可能会:
>> Z = zeros(628000000, 1, 'single');
>> Z(364000000:end) = [];
Out of memory. Type HELP MEMORY for your options.
除非Matlab在截断Z
之前做了一些巧妙的优化,否则这段代码实际上会创建一个数组(double类型!) 364000000:628000000
。 我不需要这个数组,所以我可以这样做:
>> Z = Z(1:363999999);
在这种情况下,第二个例子有效,对我的目的来说很好。 但是它为什么起作用? 如果由于中间数组364000000:628000000
所需的内存而导致Z(364000000:end) = 0
失败,那么为什么Z = Z(1:363999999)
由于中间数组1:363999999
所需的内存而失败更大? 当然,我不需要这个中间数组,并且可以对无需任何中间数组而截断我的数组的解决方案感到满意,或者,如果Matlab优化了特定的方法,则会失败。
¹原因:我正在处理数据,但不知道要预先分配多少。 我做了一个有教养的猜测,我经常分配太多。 我根据可用的内存来选择块大小,因为分割成更少的块意味着更快的代码。 所以我想避免任何不必要的内存使用。 另请参阅关于按块分配的帖子。
我在配备24GB内存的机器上运行了两个例子profile('-memory','on');
。 该分析器选项将显示分配的内存并在每行代码上释放内存。 这些应该是毛额而非净额。 我用一个简单的函数检查了净0免费和分配,并报告了总额。 但是,似乎内置命令不带.m代码来支持它们不会给分析器提供细粒度的内存报告。
我为以下代码运行了几项测试:
% truncTest.m
N = 628000000;
M = 364000000;
clear Z
Z = zeros(N,1,'single');
Z(M:end) = [];
Z(1) % just because
clear Z
Z = zeros(N,1,'single');
Z = Z(1:M);
Z(1)
对于他们的价值, N
和M
的内存分析结果是:
那么,两条线在内存分配和释放方面看起来是一样的。 也许这不是全部的事实。
所以,出于好奇,我把M
减少到200
(只有200!),而不改变N
,确实profile clear
并重新渲染。 分析索赔:
有趣的是, Z=Z(1:M);
现在实际上是瞬时的,并且Z(M:end)=[];
速度稍快一点。 正如预期的那样,两者都免费提供大约2.4GB的内存
最后,如果我们走另一个方向并设置M=600000000;
:
现在甚至Z=Z(1:M);
是缓慢的,但大约是Z(M:end)=[];
两倍 Z(M:end)=[];
。
这表明:
Z=Z(1:M);
只是捕获指定的元素,将它们存储在新的缓冲区或临时变量中,释放旧的缓冲区并将新/临时分配给数组Z
我能够让弱化的4GB机器从2.45秒变为5分钟,只需增加M
并让N
单独运行即可。 在所有情况下,肯定会选择小型M/N
Z(M:end)=[];
总是重写缓冲区,并且执行时间也随着M
增加。 实际上总是较慢,并且似乎以指数方式增加,不像Z=Z(1:M);
。 更新1 :为了好玩,我在M
的值范围内对测试进行计时:
显然比分析更多的信息。 两种方法都不是无操作,但Z=Z(1:M);
是最快的,但它可以使用接近1的M/N
的Z
的内存的两倍。
更新2 :
在R2008b之前,32位Windows中提供了一个称为mtic
(和mtoc
)的相对未知的feature
。 我仍然把它安装在一台机器上,所以我决定看看它是否提供了更多的见解,并且了解到(a)自那时以来发生了很大变化,(b)它是一个完全不同的32位MATLAB内存管理器。 不过,我将测试规模缩小到N=128000000; M=101000000;
N=128000000; M=101000000;
并看了一下。 首先, Z=Z(1:M-1);
feature mtic
Z=Z(1:M-1);
>> tic; feature mtic; Z=Z(1:M-1); feature mtoc, toc
ans =
TotalAllocated: 808011592
TotalFreed: 916009628
LargestAllocated: 403999996
NumAllocs: 86
NumFrees: 77
Peak: 808002024
Elapsed time is 0.951283 seconds.
清除,重新创建Z
,反过来:
>> tic; feature mtic; Z(M:end) = []; feature mtoc, toc
ans =
TotalAllocated: 1428019588
TotalFreed: 1536018372
LargestAllocated: 512000000
NumAllocs: 164
NumFrees: 157
Peak: 1320001404
Elapsed time is 4.533953 seconds.
在每个度量( TotalAllocated
, TotalFreed
, NumAllocs
等)中, Z(M:end) = [];
效率低于Z=Z(1:M-1);
。 我期望可以通过检查这些N
和M
值来辨别内存中发生了什么,但我们会猜测旧的MATLAB