Hacker News

Waarom is de eerste C++ (m)allocatie altijd 72 KB?

Ontdek waarom uw eerste C++-geheugentoewijzing 72 KB vraagt ​​in plaats van de verwachte bytes. Ontdek de malloc-internals en de geheugenbeheerlagen van het besturingssysteem uitgelegd.

6 min gelezen

Mewayz Team

Editorial Team

Hacker News

Het mysterie achter uw eerste C++-toewijzing

Je schrijft een eenvoudig C++ programma. Een enkele nieuwe int. Vier bytes. Je start strace of je favoriete geheugenprofiler op, en daar is het: je proces heeft zojuist ongeveer 72 KB van het besturingssysteem aangevraagd. Niet 4 bytes. Niet 64 bytes. Een volledige 72 KB. Als je ooit naar dat aantal hebt gestaard en je hebt afgevraagd of je gereedschap tegen je loog, ben je niet de enige. Dit ogenschijnlijk bizarre gedrag is een van de meest gestelde vragen onder C++-ontwikkelaars die voor het eerst in het interne geheugen graven, en het antwoord neemt ons mee op een fascinerende reis door de lagen tussen je code en de daadwerkelijke hardware.

Wat er gebeurt als u nieuw belt

Om het cijfer van 72 KB te begrijpen, moet u de volledige toewijzingsketen volgen. Wanneer je C++-code new int uitvoert, vertaalt de compiler dat in een aanroep naar operator new, die op de meeste Linux-systemen vanuit glibc naar malloc delegeert. Maar malloc vraagt ​​de kernel niet rechtstreeks om 4 bytes geheugen. De kernel werkt in pagina's (meestal 4 KB op x86_64) en de kosten van een systeemaanroep zijn enorm in vergelijking met een eenvoudige geheugentoegang. Het aanroepen van brk() of mmap() voor elke individuele toewijzing zou elk niet-triviaal programma tot stilstand brengen.

In plaats daarvan fungeert de geheugenallocator van glibc (een implementatie genaamd ptmalloc2, die zelf afstamt van de klassieke dlmalloc van Doug Lea) als tussenpersoon. Het vraagt ​​vooraf grote blokken geheugen van de kernel en snijdt ze vervolgens in kleinere stukken als uw programma ze nodig heeft. Dit is de fundamentele reden waarom uw eerste toewijzing van 4 bytes een veel groter verzoek aan het besturingssysteem activeert. De allocator is niet verspillend. Het is strategisch.

Het ontleden van de 72 KB: waar de bytes naartoe gaan

De initiële toewijzingsoverhead is afkomstig van verschillende afzonderlijke componenten die de runtime moet initialiseren voordat deze u zelfs maar één byte bruikbaar geheugen kan opleveren. Als u elk onderdeel begrijpt, wordt uitgelegd waarom het nummer daar terechtkomt.

Ten eerste initialiseert glibc's malloc de hoofdarena: de primaire boekhoudstructuur die alle toewijzingen op de hoofdlijn bijhoudt. Deze arena bevat metagegevens voor de heap, vrije-lijstaanwijzers en bin-structuren voor verschillende toewijzingsgroottes. De allocator verlengt de programma-onderbreking via sbrk(), en de initiële uitbreiding wordt bepaald door een interne parameter genaamd M_TOP_PAD, die standaard 128 KB opvulling heeft. Het daadwerkelijke initiële verzoek wordt echter aangepast aan de uitlijning van de pagina en de bestaande onderbrekingspositie, wat vaak resulteert in een kleiner eerste verzoek, dat meestal in de buurt van dat bedrag van 72 KB terechtkomt bij een pas gestart proces.

💡 WIST JE DAT?

Mewayz vervangt 8+ zakelijke tools in één platform

CRM · Facturatie · HR · Projecten · Boekingen · eCommerce · POS · Analytics. Voor altijd gratis abonnement beschikbaar.

Begin gratis →

Ten tweede initialiseert de allocator sinds glibc 2.26 een thread-local cache (tcache) bij het eerste gebruik. De tcache bevat 64 bins (één per kleine toewijzingsgrootteklasse), die elk maximaal 7 in de cache opgeslagen chunks kunnen bevatten. De tcache_perthread_struct zelf verbruikt ongeveer 1 KB, maar de handeling van het initialiseren ervan activeert de bredere arena-opstelling. Ten derde heeft de C++-runtime al toewijzingen uitgevoerd voordat main() zelfs maar wordt uitgevoerd - statische constructors, iostream-bufferinitialisatie voor std::cout en vrienden, en locale-instellingen dragen allemaal bij aan die initiële heap-voetafdruk.

Het Arena-systeem en waarom voorafgaande toewijzing slim is

De beslissing om vooraf een substantieel deel van het geheugen toe te wijzen in plaats van het stukje bij beetje op te vragen, is geen toevallige implementatie. Het is een bewuste technische afweging die geworteld is in tientallen jaren ervaring met systeemprogrammering. Elke aanroep van brk() of mmap() omvat een contextwisseling van gebruikersruimte naar kernelruimte, wijziging van de virtuele geheugentoewijzingen van het proces en mogelijke updates van de paginatabel. Op moderne hardware kost een enkele systeemoproep grofweg 100 tot 200 nanoseconden – triviaal op zichzelf, catastrofaal op schaal.

Overweeg een programma dat tijdens de initialisatie 10.000 kleine toewijzingen maakt. Zonder voorafgaande toewijzing zou dat 10.000 systeemaanroepen betekenen, wat ongeveer 1 tot 2 milliseconden aan pure overhead kost. Met een arena-gebaseerde allocator wordt de eerste toewijzing geactiveerd

Build Your Business OS Today

From freelancers to agencies, Mewayz powers 138,000+ businesses with 207 integrated modules. Start free, upgrade when you grow.

Create Free Account →

Frequently Asked Questions

Waarom duurt het eerste `new` of `malloc` aanroep zo lang?

De eerste aanroep lijkt traag omdat de geheugenbeheerder van de C++-runtime (bijv. de glibc-allocator) zichzelf moet initialiseren. Dit omvat het reserveren van dat initiële blok geheugen (72 KB) van het besturingssysteem en het opzetten van interne datastructuren voor toekomstige, snellere toewijzingen. Het is een eenmalige opstartkost. Voor prestatiekritische code kan het gebruik van een geheugenpool, zoals beschikbaar in toolsets zoals Mewayz met 207 modules, deze vertraging elimineren door vooraf geheugen te reserveren.

Kan ik dit 72 KB geheugenblok aanpassen of verkleinen?

Ja, dit is vaak mogelijk, maar platformafhankelijk. Bij gebruik van glibc kunt u de `M_MMAP_THRESHOLD` omgevingsvariabele instellen om de drempel te wijzigen waaronder geheugen vanaf de heap wordt toegewezen in plaats van via mmap. Echter, het verkleinen kan leiden tot meer systeemaanroepen en fragmentatie. Voor fijnmazige controle over het geheugenbeheer van uw applicatie, bieden gespecialiseerde allocators of bibliotheken meer flexibiliteit zonder de standaardsysteembibliotheek te hoeven aanpassen.

Is dit gedrag hetzelfde op Windows met Visual C++?

Nee, de implementatie verschilt. De MSVC-runtime (Visual C++) gebruikt een ander allocatiealgoritme en zal een andere initiële grootte reserveren. Het onderliggende principe is echter hetzelfde: de runtime-bibliotheek initialiseert zijn geheugenbeheersubsysteem bij de eerste aanroep. De specifieke grootte kan variëren, maar het doel is identiek: het voorbereiden van een pool geheugen voor efficiënte toekomstige toewijzingen, waardoor de overhead van herhaalde systeemaanroepen wordt vermeden.

Heeft dit invloed op de prestaties van mijn applicatie?

De impact is meestal verwaarloosbaar voor de meeste applicaties, omdat het een eenmalige kost is bij opstart. Het wordt pas een probleem in scenario's met extreem lage latentie of in embedded systemen met zeer beperkt geheugen. Voor die gevallen is het analyseren van geheugentoewijzingen cruciaal. Een tool zoals Mewayz kan helpen bij het profilen en optimaliseren van geheugengebruik, zodat ontwikkelaars knelpunten kunnen identificeren en gepaste allocatiestrategieën kunnen implementeren voor maximale efficiëntie.

Probeer Mewayz Gratis

Alles-in-één platform voor CRM, facturatie, projecten, HR & meer. Geen creditcard nodig.

Begin vandaag nog slimmer met het beheren van je bedrijf.

Sluit je aan bij 30,000+ bedrijven. Voor altijd gratis abonnement · Geen creditcard nodig.

Klaar om dit in de praktijk te brengen?

Sluit je aan bij 30,000+ bedrijven die Mewayz gebruiken. Voor altijd gratis abonnement — geen creditcard nodig.

Start Gratis Proefperiode →

Klaar om actie te ondernemen?

Start vandaag je gratis Mewayz proefperiode

Alles-in-één bedrijfsplatform. Geen creditcard vereist.

Begin gratis →

14 dagen gratis proefperiode · Geen creditcard · Altijd opzegbaar