Memory-efficient way to truncate large array in Matlab

感情迁移 提交于 2019-11-27 21:21:35

I ran both examples on a machine with 24GB of RAM with profile('-memory','on');. This profiler option will show memory allocated and freed on each line of code. These are supposed to be gross not net amounts. I checked with a simple function that has net 0 free and alloc and it reported the gross amounts. However, it seems likely that builtin commands with no .m code to back them do not give fine-grained memory reporting to the profiler.

I ran a couple tests for the following code:

% 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)

For what they are worth, the memory profiling results for this N and M are:

Well, both lines look the same in terms of memory allocated and freed. Maybe that's not the whole truth.

So, out of curiosity I decreased M to 200 (just 200!) without changing N, did profile clear and reran. Profiling claims:

Interestingly, Z=Z(1:M); is practically instantaneous now, and Z(M:end)=[]; is a little faster. Both free about 2.4GB of memory, as expected.

Finally, if we go the other direction and set M=600000000;:

Now even Z=Z(1:M); is slow, but about twice as fast as Z(M:end)=[];.

This suggests:

  1. Z=Z(1:M); just grabs the indicated elements, stores them in a new buffer or temporary variable, releases the old buffer and assigns the new/temporary to the array Z. I was able to make my weaker 4GB machine go from 2.45 seconds to thrashing the page file for 5 minutes just by increasing M and leaving N alone. Definitely prefer this option for small M/N, probably in all cases.
  2. Z(M:end)=[]; always rewrites the buffer, and execution time increases with M too. Actually always slower, and seems to increase exponentially, unlike Z=Z(1:M);.
  3. Memory profiling does not give fine-grained information about these builtin operations and should not be misinterpreted as giving a total of memory freed and allocated over the commands execution, but rather a net change.

UPDATE 1: Just for fun I timed the tests at a range of values of M:

Clearly more informative than the profiling. Both methods are not no-ops, but Z=Z(1:M); is fastest, but it can use almost double the memory of Z for M/N near 1.

UPDATE 2:

A relatively unknown feature called mtic (and mtoc) were available in 32-bit Windows prior to R2008b. I still have it installed on one machine, so I decided to see if that provides any more insight, with the understanding that (a) much has changed since then and (b) it's a completely different memory manager used in 32-bit MATLAB. Still, I reduced the test size to N=128000000; M=101000000; and had a look. First, 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.

Clearing up, recreating Z, the other way:

>> 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.

In every metric (TotalAllocated, TotalFreed, NumAllocs, etc.), Z(M:end) = []; is less efficient than Z=Z(1:M-1);. I expect it is possible to discern what is going on in memory by examining these numbers for these values of N and M, but we'd be guessing about an old MATLAB

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!