15

我在 Matlab 中有一个大型(多 GB)数组,我想截断它¹。天真地,我认为截断不需要太多内存,但后来我意识到它可能可以:

>> Z = zeros(628000000, 1, 'single');
>> Z(364000000:end) = [];
Out of memory. Type HELP MEMORY for your options.

除非 Matlab 做一些巧妙的优化,否则在截断之前Z,这段代码实际上会创建一个数组(双精度型!)364000000:628000000。我不需要这个数组,所以我可以这样做:

>> Z = Z(1:363999999);

在这种情况下,第二个示例有效,并且适合我的目的。但为什么它会起作用?如果Z(364000000:end) = 0由于中间数组所需的内存而失败364000000:628000000,那么为什么不会Z = Z(1:363999999)由于中间数组所需的内存而失败1:363999999,即更大?当然,我不需要这个中间数组,我会很高兴有一个解决方案可以在没有任何中间数组的情况下截断我的数组,或者如果 Matlab 优化了一个特定的方法。

  • 有没有办法在不创建中间索引数组的情况下截断数组?
  • 如果不是,上述任何一种方法是否比另一种更节省内存(看起来不是)?如果是这样,为什么?Matlab真的在这两个例子中都创建了中间数组吗?

¹原因:我正在处理数据,但不知道要预分配多少。我做了一个有根据的猜测,我经常分配太多。我根据可用内存选择块大小,因为分成更少的块意味着更快的代码。所以我想避免任何不必要的内存使用。另请参阅有关按块分配的帖子

4

1 回答 1

15

我在具有 24GB RAM 的机器上运行了这两个示例profile('-memory','on');。此分析器选项将显示在每一行代码上分配和释放的内存。这些应该是总额而不是净额。我检查了一个简单的函数,它有 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)

N对于它们的价值,内存分析结果M是:

在此处输入图像描述

好吧,就分配和释放的内存而言,这两行看起来都是一样的。也许这不是全部真相。

所以,出于好奇,我减少M200(只有 200 个!)没有改变N,做了profile clear并重新运行。分析声明:

在此处输入图像描述

有趣的是,Z=Z(1:M);现在几乎是瞬时Z(M:end)=[];的,而且速度更快。正如预期的那样,两者都释放了大约 2.4GB 的内存。

最后,如果我们去另一个方向并设置M=600000000;

在此处输入图像描述

现在 evenZ=Z(1:M);很慢,但大约Z(M:end)=[];.

这表明:

  1. Z=Z(1:M);只需抓取指定的元素,将它们存储在新缓冲区或临时变量中,释放旧缓冲区并将新的/临时的分配给数组Z。我能够使我较弱的 4GB 机器从 2.45 秒变为 5 分钟,只需增加 M并保持N不变。M/N对于 small ,可能在所有情况下都绝对更喜欢这个选项。
  2. Z(M:end)=[];总是重写缓冲区,并且执行时间也随之增加M。实际上总是较慢,并且似乎呈指数增长,不像Z=Z(1:M);.
  3. 内存分析不会提供有关这些内置操作的细粒度信息,不应被误解为在命令执行时释放和分配的内存总量,而是净变化。

更新 1:只是为了好玩,我将测试计时在以下值范围内M

在此处输入图像描述

显然比分析提供更多信息。这两种方法都不是无操作,但Z=Z(1:M);速度最快,但它可以使用几乎两倍于Zfor M/Nnear 1 的内存。

更新 2

R2008b 之前的 32 位 Windows 中提供了一个相对未知的feature称为mtic(and )。mtoc我仍然将它安装在一台机器上,所以我决定看看这是否能提供更多洞察力,因为我知道(a)从那时起发生了很大变化,(b)它是 32 位 MATLAB 中使用的完全不同的内存管理器。尽管如此,我还是将测试大小减小到N=128000000; M=101000000;并进行了查看。首先,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.

在每个度量(TotalAllocatedTotalFreedNumAllocs等)中,Z(M:end) = [];效率都低于Z=Z(1:M-1);。我希望可以通过检查这些数字中的这些值来辨别内存中发生了什么NM,但我们会猜测旧的 MATLAB

于 2013-10-29T01:52:15.837 回答