Memory footprint of multi-dimensional arrays
Simen Kjaeraas
simen.kjaras at gmail.com
Fri Apr 18 14:04:16 PDT 2008
On Fri, 18 Apr 2008 18:15:45 +0200, BCS <BCS at pathlink.com> wrote:
> Ben Mitchell wrote:
>> So, I was watching my D program eat up ~1GB of ram doing something my
>> back of the envelope calculation said should only be taking a few
>> hundred MB max, and I started playing around. Turns out that if I do:
>> ubyte[][] b = new ubyte[][](3, 10485760);
>> It takes about 30MB of main memory, as would be expected. If, on the
>> other hand, I reverse the order of the indexing and do:
>> ubyte[][] b = new ubyte[][](10485760, 3);
>> It takes about 250MB of main memory. This seems totally absurd to me;
>> I can only assume this is because it's an array of (potentially
>> arbitrary size) dynamic arrays, and there's ~220MB of bookkeeping
>> information being stored. Is there any way around this? Can I
>> somehow tell the compiler it's a symmetric array? Can I make a dynamic
>> array of static arrays of size 3? I can reverse the indexing if I have
>> to, but it would make the rest of my code very counter-intuitive, and
>> it just doesn't seem like it should make an order of magnitude
>> difference in memory usage.
>> - Ben
>
> one (kinda ugly) solution would be to allocate the whole thing as a
> single huge ubyte[] array and slice out the 1M 3 byte arrays:
>
>
> auto tmp = new ubyte[](3*10485760 + 5);
>
> ubyte[][] b;
> b.length = 10485760;
> foreach(uint i, ref bp; b) bp = tmp[i*3.. (i+1)*3];
>
> A little template magic might be able to do this recursively for nested
> dynamic arrays
Wouldn't that end up taking just as much space? b would be an array of
10485760 slices, each having a pointer/length pair taking up 8 bytes each,
no?
Might save some due to GC wanting bigger slices than 3 bytes, but still.
Now, using a struct with overloaded opIndex (and opSlice, if you want)
should be lighter. Something like this (untested)?
struct Foo
{
ubyte[] data;
size_t sz1, sz2;
static Foo opCall(size_t size1, size_t size2)
{
Foo tmp;
tmp.data.length = size1 * size2;
tmp.sz1 = size1;
tmp.sz2 = size2;
return tmp;
}
ubyte[] opIndex(size_t index)
{
return data[index * size2..index * size2 + size1];
}
void opIndexAssign(ubyte[] value, size_t index)
{
data[index * size2..index * size2 + size1] = value;
}
}
-- Simen
More information about the Digitalmars-d
mailing list