I en kommentar til mit indlæg om tilgængelig hukommelse i .NET applikationer skriver Jonathan Jørgensen følgende meget relevante kommentar, ”Maks. 2GB per objekt i 64bit applikationer”. Jeg var godt klar over, at denne begrænsning eksisterer i 32 bit .NET, men jeg var faktisk ikke opmærksom på, at den også gælder i 64 bit-verdenen.
Jonathan fortsætter, ”Det er dog de færreste der vil opleve disse problemer da klasser (reference types) som eksempelvis List jo selv referer til flere objekter internt.”
Det kan godt være, at der ikke er mange, der vil opleve problemet, men hvis jeg forstår Jonathan korrekt, tager han desværre fejl med hensyn til List<T>. Problemet er nemlig, at List<T> benytter et array til at gemme sine referencer, og dette array er naturligvis også underlagt 2 GB-grænsen. Ergo er List<T> og andre typer, der benytter arrays begrænset i størrelse.
Det har den ret overraskende effekt, at siden 64 bit referencer er dobbelt så store som 32 bit referencer, kan en instans af List<T> kun rumme halvt så mange referencer under 64 bit .NET i forhold til samme liste under 32 bit .NET. Det er ikke just indlysende, og det vil betyde, at applikationer, der kører fint under 32 bit .NET risikerer at fejle med OutOfMemoryException under 64 bit!
Et array kan i teorien være 2 GB stort på 32 bit .NET. I praksis er den en anelse mindre, da selve array-instansen også har det sædvanlige overhead, der kendes fra referencetyper. Derfor vil List<T> kunne rumme ca. 2 GB / 4 elementer på 32 bit, mens tallet er ca. 2 GB / 8 elementer på 64 bit.
I teorien kan vi derfor have 536.870.897 referencer i en List<T> på 32 bit, men som min forrige artikel illustrerede, kan vi ikke regne med at kunne allokere mere end ca. 1,5 GB sammenhængende hukommelse under 32 bit Windows, og derfor vil vi i praksis ikke kunne oprette en liste med det antal elementer. Det faktiske antal elementer afhænger af det største sammenhængende område i processens adresserum.
På 64 bit er resultatet dog endnu mere begrænset. Her vil vi maksimalt kunne allokere en List<T> med 268.435.448 referencer.
Under 32 bit Windows vil vi i bedste fald kunne oprette et array med ca. 1,5 GB / 4, svarende til ca. 400.000.000 elementer. Det er en del mere end det maksimale antal elementer i et array under 64 bit, og derfor kan vi komme i den bizarre situation, at det faktisk kan give bagslag at flytte sin applikation til 64 bit.
Det er ikke svært, at lave sine egne klasser, der kommer uden om denne begrænsning ved f.eks. at bruge en hægtet liste eller ved at splittet indholdet op i et antal arrays, når det bliver nødvendigt, men det ville have været rart, om standardtyperne under 64 bit .NET havde givet bedre eller i det mindste bare de samme muligheder som under 32 bit.