Link to home
Start Free TrialLog in
Avatar of jon_rs
jon_rs

asked on

Delphi Dynamic Array Contiguity

I have an application that dumps data from a complicated dynamic array to disk and then reads it back in again at a later point to minimize memory usage.

The array (of singles) has four dimensions and is created in two steps:

   
 SetLength(SDVuser,MaxRegionTypes+1);
    for i := 0 to MaxRegionTypes do
      SetLength(SDVuser[i],MaxSubRegions[i]+1,  MaxSimDailyVars+1,  MaxDays+1);

Open in new window


So in others words, the first dimension is created first and then the 2nd/3rd/4th dimensions are created next because the size of the second dimension varies.

The writing to and reading from file F (file of single) is done using BlockWrite and BlockRead commands:

       
 for rt := 0 to MaxRegionTypes do
          begin
            RecordSize := (MaxSubRegions[rt]+1)*
                          (MaxSimDailyVars+1) *
                          (MaxDays+1);
            BlockRead(F,SDVuser[rt,0,0,0],RecordSize);
          end;

Open in new window


This assumes that the 2nd/3rd/4th dimensions of the SDVuser array are CONTIGUOUS in memory.  Documentation and on-line comment that I can see on dynamic arrays suggests this is true.

But I sometimes get Range Check errors associated with the BlockRead which I am thinking might be caused by non-contiguity.  I am also getting odd exceptions occurring elsewhere which again I think may be caused by memory being trampled because the array is not in fact contiguous.

Question 1: Does the SetLength para create a contiguous block of memory for the 3 dimensions I create in one go?
Question 2: Do the secondary SetLength operations cause the entire 4 dimensional structure to be recreated each time to ensue that the WHOLE array is contiguous - my observation is that assuming this causes lots more problems elsewhere and so I have avoided making this assumption.

Hope someone can clarify the situation

Best wishes

Jon
Avatar of MerijnB
MerijnB
Flag of Netherlands image

In Delphi dynamic arrays are put in one single large memory block.

I'm not 100% sure, but I think that when you do a SetLength() on the first dimension, all the dynamic arrays in the second dimension will be set to 0 length (or to unknown status).

So in short:

1) no, only for the first dimension
2) yes

One note: depending on which Delphi version you are using large dynamic arrays can cause problems for the standard memory manager (memory fragmentation = memory leak while you don't actually leak memory).
SOLUTION
Avatar of aikimark
aikimark
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jon_rs
jon_rs

ASKER

Hi both

Thanks for your responses.
I have taken a step back and rewritten the code so that it makes NO assumptions about contiguity of  a multi dimensioned dynamic array and my memory problems have gone away.

So I think in summary:

A single dimensioned dynamic array IS contiguous
An array of variable sized arrays constructed in a dynamic array will almost certainly NOT be contiguous (although elements of the individual dimensions MIGHT be).
Relying on any sort of contiguity of a multi-dimensioned dynamic array is dangerous and to be avoided.

Jon
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jon_rs

ASKER

MerijnB

Thanks.  I think my original question was not as clear as it could have been :-)

As you say I can see no reason why the second set of 3 dimensional arrays should not be contiguous, but my findings suggest that if you pass the starting address of that part of the array to the BlockWrite/BlockRead you don't always get want you think you might.

My solution has been to create a new single dimensioned array (which definitely is contiguous) and to copy (element by element) the stuff in the 3-dimensional array into that contiguous block and then to write that out, and then to reverse the process for a BlockRead.  This makes the whole thing stable again.

Jon