winapivirtualalloc

How to (temporary) release memory from VirtualAlloc?


When using VirtualAlloc I can (ab)use the following property to simplify memory management.

Actual physical pages are not allocated unless/until the virtual addresses are actually accessed.

I run the following code to allocate the block.

type
  PArrayMem = ^TArrayMem;    //pointer
  TArrayMem = packed record  //as per documentation
    RefCount: Integer;
    Length: NativeInt;
    Elements: Integer;
  end;

var
  a: array of integer;  //dynamic array, structure see above

procedure TForm38.Button1Click(Sender: TObject);
const
  AllocSize = 1024 * 1024 * 1024; //1 GB
var
  ArrayMem: PArrayMem;
begin
  //SetLength(a, 1024*1024*1024); //1G x 8*16
  ArrayMem:= VirtualAlloc(nil, AllocSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);
  ArrayMem.RefCount:= 1;
  ArrayMem.Length:= AllocSize div SizeOf(Integer);
  a:= @ArrayMem.Elements;   //a:= AddressOf(elements)
  a[1]:= 10;        //testing, works
  a[0]:= 4;
  a[500000]:= 56;   //Works, autocommits, only adds a few k to the used memory
  button1.Caption:= IntToStr(a[500000]);  //displays '56'
end;

All this works great. If my structure grows to 1.000.000 elements everything works.
However suppose afterwards my structure shrinks back to 1.000 elements.

How do I release the RAM so that it will get auto-magically committed when needed again?

WARNING
David warned my that allocating an committing large (huge) continous pages of memory carries a large cost.
So it may be more advantageous to split up the array in smaller blocks and abstract away the internals using a class/record.


Solution

  • You can decommit pages using VirtualFree passing the MEM_DECOMMIT flag. Then you can commit again using VirtualAlloc.

    Or you may use the DiscardVirtualMemory function introduced in Windows 8.1.

    Use this function to discard memory contents that are no longer needed, while keeping the memory region itself committed. Discarding memory may give physical RAM back to the system. When the region of memory is again accessed by the application, the backing RAM is restored, and the contents of the memory is undefined.

    You may find something useful in the comments to this related question: New Windows 8.1 APIs for virtual memory management: `DiscardVirtualMemory()` vs `VirtualAlloc()` and `MEM_RESET` and `MEM_RESET_UNDO`