{$MODE OBJFPC}
{$define ALLOCATE_TRUE_SIZE}
program _LargeArray;
uses
sysutils,
Windows
;
type
TELEMENT_RANGE = 1..8192;
const
WIDTH = 10;
ELEMENT_COUNT = high(TELEMENT_RANGE);
{ 2GB - 1MB for safety }
BLOCK_HI_SIZE = 2 * (1024 * 1024 * 1023); { one meg short of actual size }
type
n = 0..1849;
TSEQUENCE = array[1..13] of n;
PINNER_RECORD = ^TINNER_RECORD;
TINNER_RECORD = record
sq : TSEQUENCE;
ar : array[TELEMENT_RANGE] of record
s : TSEQUENCE;
x : longint;
end
end;
const
{$ifdef ALLOCATE_TRUE_SIZE}
ALLOC_HI_COUNT = BLOCK_HI_SIZE div sizeof(TINNER_RECORD);
ALLOC_LO_COUNT = ELEMENT_COUNT - ALLOC_HI_COUNT;
{$else}
ALLOC_HI_COUNT = 16; { counts arbitrarily chosen }
ALLOC_LO_COUNT = 8;
{$endif}
var
OuterRecordStaticSize : qword;
{ the memory blocks that hold the records }
MemoryBlocks : packed array[0..1] of PINNER_RECORD;
{ the array of pointers to inner records }
RecordsArray : array[TELEMENT_RANGE] of PINNER_RECORD;
i : TELEMENT_RANGE;
p : PINNER_RECORD;
SCOPE : DWORD;
begin
writeln;
writeln;
writeln(' approx size of above 2GB block : ', BLOCK_HI_SIZE:WIDTH);
writeln(' Inner record size : ', sizeof(TINNER_RECORD):WIDTH);
writeln;
OuterRecordStaticSize := ELEMENT_COUNT * sizeof(TINNER_RECORD);
writeln(' Outer record size : ', OuterRecordStaticSize:WIDTH);
if OuterRecordStaticSize >= 1700000000 then { about 1.7GB }
begin
writeln;
writeln(' data structure is too large for a 32bit program');
writeln(' that is not large address [ > 2GB ] space aware');
end;
writeln;
writeln(' will allocate ', ALLOC_HI_COUNT:4, ' records in the block above 2GB');
writeln(' will allocate ', ALLOC_LO_COUNT:4, ' records in the block below the 2GB line');
repeat { scope delimiter - NOT a loop }
MemoryBlocks[0] := VirtualAlloc(nil, { anywhere is fine }
ALLOC_HI_COUNT * sizeof(TINNER_RECORD),
MEM_COMMIT or MEM_RESERVE,
PAGE_READWRITE);
MemoryBlocks[1] := VirtualAlloc(nil, { anywhere is fine }
ALLOC_LO_COUNT * sizeof(TINNER_RECORD),
MEM_COMMIT or MEM_RESERVE,
PAGE_READWRITE);
if (MemoryBlocks[0] = nil) or (MemoryBlocks[0] = nil) then
begin
writeln;
writeln;
writeln(' failed to allocate the necessary memory blocks');
break;
end;
writeln;
writeln(' block ABOVE the 2GB line is at : ', IntToHex(ptruint(MemoryBlocks[0]), 0):10);
writeln(' block below the 2GB line is at : ', IntToHex(ptruint(MemoryBlocks[1]), 0):10);
{ populate the array of pointers to inner blocks }
p := PINNER_RECORD(MemoryBlocks[0]);
for i := low(TELEMENT_RANGE) to TELEMENT_RANGE(ALLOC_HI_COUNT) do
begin
RecordsArray[i] := p;
{$ifndef ALLOCATE_TRUE_SIZE}
{ mark the records for testing and verification purposes only }
FillChar(p^, sizeof(p^), byte(i));
{$endif}
inc(p);
end;
p := PINNER_RECORD(MemoryBLocks[1]);
for i := TELEMENT_RANGE(ALLOC_HI_COUNT + 1)
to TELEMENT_RANGE(ALLOC_HI_COUNT + ALLOC_LO_COUNT) do
begin
RecordsArray[i] := p;
{$ifndef ALLOCATE_TRUE_SIZE}
{ mark the records for testing and verification purposes only }
FillChar(p^, sizeof(p^), byte(i));
{$endif}
inc(p);
end;
{ output the pointers in RecordsArray }
writeln;
for i := low(RecordsArray)
to TELEMENT_RANGE(ALLOC_LO_COUNT + ALLOC_HI_COUNT) do
begin
write(' ', ord(i):4, ':', IntToHex(ptruint(RecordsArray[i]), 0):10);
if ord(i) mod 4 = 0 then writeln;
end;
until SCOPE = SCOPE;
writeln;
writeln;
writeln('press ENTER/RETURN to end this program');
readln;
end.