我在 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);
在这种情况下,第二个示例有效,并且适合我的目的。但是为什么它会起作用?如果 Z(364000000:end) = 0
由于中间数组 364000000:628000000
所需的内存而失败,那么为什么 Z = Z(1: 363999999)
因中间数组1:363999999
所需的内存而失败,即更大?当然,我需要这个中间数组,我会很高兴有一种解决方案可以截断我的数组而没有任何中间数组,或者如果 Matlab 优化了特定方法,则失败了。
- 有什么方法可以在不创建中间索引数组的情况下截断数组?
- 如果不是,上述任何一种方法是否比另一种更节省内存(似乎不是)?如果是这样,为什么? Matlab 真的在这两个例子中都创建了中间数组吗?
¹原因:我正在处理数据,但不知道要预分配多少。我做了一个有根据的猜测,我经常分配太多。我根据可用内存选择 block 大小,因为分成更少的 block 意味着更快的代码。所以我想避免任何不必要的内存使用。另见 this post on allocating by chunk .
最佳答案
我在具有 profile('-memory','on');
的 24GB RAM 机器上运行了这两个示例。此分析器选项将显示在每一行代码上分配和释放的内存。这些应该是总额而不是 Netty 。我检查了一个简单的函数,它有 net 0 free 和 alloc,它报告了总金额。但是,似乎没有 .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)
对于它们的值(value),此 N
和 M
的内存分析结果是:
嗯,就分配和释放的内存而言,这两行看起来是相同的。也许这不是全部真相。
所以,出于好奇,我在不更改 N
的情况下将 M
减少到 200
(只有 200 个!),profile clear
并重新运行。分析声明:
有趣的是,Z=Z(1:M);
现在几乎是瞬时的,而 Z(M:end)=[];
快了一点。正如预期的那样,两者都释放了大约 2.4GB 的内存。
最后,如果我们换个方向,设置M=600000000;
:
现在即使 Z=Z(1:M);
也很慢,但大约是 Z(M:end)=[]; 的 两倍
.
这表明:
Z=Z(1:M);
只是抓取指定的元素,将它们存储在新缓冲区或临时变量中,释放旧缓冲区并将新的/临时的分配给数组Z
。我能够通过 increasingM
并单独留下N
使我较弱的 4GB 机器从 2.45 秒变为 5 分钟的页面文件抖动.对于小的M/N
,绝对更喜欢这个选项,可能在所有情况下。Z(M:end)=[];
总是重写缓冲区,执行时间也随着M
的增加而增加。实际上总是更慢,而且似乎呈指数增长,这与Z=Z(1:M);
不同。- 内存分析不会提供有关这些内置操作的细粒度信息,不应被误解为在命令执行过程中释放和分配的内存总量,而是净变化。
更新 1:只是为了好玩,我在 M
的值范围内对测试进行计时:
显然比分析提供更多信息。两种方法都不是空操作,但是 Z=Z(1:M);
最快,但是对于 M 可以使用几乎是
在 1 附近。Z
两倍的内存/N
更新 2:
在 R2008b 之前的 32 位 Windows 中提供了一个相对未知的 feature
,称为 mtic
(和 mtoc
)。我仍然将它安装在一台机器上,所以我决定看看这是否能提供更多洞察力,因为我知道(a)从那时起发生了很大变化,(b)它是 32 位 MATLAB 中使用的完全不同的内存管理器。尽管如此,我还是将测试大小减小到 N=128000000; M=101000000;
看看。一、feature mtic
for 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
关于arrays - 在 Matlab 中截断大数组的内存有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19633192/