Jednoho krásného dne Váš program zjistí, že trpí nedostatkem paměti. Přirozeným krokem je přechod na 64bit aplikace, ale existuje i jiná možnost. U EXE (resp. PE souboru) se dá specifikovat flag IMAGE_FILE_LARGE_ADDRESS_AWARE. Tento flag byl původně určen pro speciální mód 32bit Windows, kdy místo normálních cca 2GB paměti pro 32bit proces nabízel celých úžasných 3GB volné paměti. Praktická využitelnost tedy nic moc, protože tento mód Windows se moc nepoužíval.
Situace se obrátila s příchodem 64bit Windows (jen aby nedošlo k nedorozumnění - dávejte pozor kdy mluvím o 32bit procesu, kdy o 32bit Windows a kdy o 64bit Windows).
64bit Windows kromě možnosti 64bit aplikací (které mají dostupnou paměť prakticky bez omezení) vylepšují podporu 32bit aplikací v uvedeném módu. Taková aplikace dostane do vínku místo klasických 2GB nebo 3GB z předchozího módu pěkných skoro celých 4GB paměti - což není vůbec špatné. Doufám, že je jasné, že je vhodné mít dostatečnou fyzickou paměť, jinak to moc nemá smysl.
Upozorňuji, že následující není vhodné pro staré verze Delphi, které na to vážně nejsou připraveny. Jako minimální bych tak odhadoval D2007. Pokud máte něco od cca XE (tipuji díky přípravám na 64bit) nebo XE2 (tam určitě k vůli podpoře 64bit) tak by to mělo být OK. Pokud mi nevěříte ohledně starých verzích, tak určitě použijte FastMM (a to v nějaké rozumné verzi) a něco dejte na dobročinnost, třeba se na Vás štěstí usměje.
Celý trik je v {$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}, což dá linkeru informaci o nastavení flagu PE souboru. Jak jistě víte, SetPEFlags je jednocestný - cokoliv se přes něj nastavuje je OR s dalšími volbami (některé se přímo nastavují v Options projektu) a není cesty zpět. Ideálně nastavit v DPR.
program Project36;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
var
m: TMemoryStatusEx;
p: Pointer;
begin
FillChar(m, SizeOf(m), 0);
m.dwLength := SizeOf( m );
try
repeat
GetMem(p, MAXINT div 100);
FillChar(m, SizeOf(m), 0);
m.dwLength := SizeOf( m );
GlobalMemoryStatusEx(m);
writeln(m.ullAvailVirtual, ' ', Format('%p', [p]));
until false;
except
end;
readln;
end.
Pár poznámek: FastMM (tj. def. paměťový manažer Delphi) automaticky alokuje paměť (resp. nejméně velké bloky - dříve jsem psal o způsobu přidělování ve FastMM) shora dolů (pokud máte samostatný FastMM tak je tam na to option, který je ale ve verzi z Delphi automaticky nastaven). To znamená, že nejdříve bude přidělena paměť ze zadní části adresového prostoru, což v důsledku má pozitivní vliv na případné chyby z důvodu vysokých adres (a nejen to).
V uvedeném programu se opakovaně vypisuje dostupná virtuální paměť a alokují se velké bloky dokud paměť nedojde. Zároveň se vypisuje adresa přiděleného fláku paměti (pro ověření TOP-DOWN alokace). Jen pro jistotu: při Out-of-memory není dostupná paměť nula, ale něco pod velikost požadovaného bloku. Vyzkoušejte si běh s nastavením flagu i bez něho. A samozřejmě vše je bez záruky.