Miért mindig 72 KB az első C++ (m)allokáció?
Fedezze fel, hogy az első C++ memóriakiosztás miért kér 72 KB-ot a várt bájtok helyett. Fedezze fel a malloc belső és az operációs rendszer memóriakezelési rétegeit.
Mewayz Team
Editorial Team
Az első C++ kiosztás mögött rejlő rejtély
Írsz egy egyszerű C++ programot. Egyetlen új int. Négy bájt. Beindítja a strace-t vagy kedvenc memóriaprofilját, és ott van – a folyamat éppen nagyjából 72 KB-ot kért az operációs rendszertől. Nem 4 bájt. Nem 64 bájt. Teljes 72 KB. Ha valaha is bámulta ezt a számot, és azon töprengett, hogy a szerszámai hazudtak-e, akkor nincs egyedül. Ez a látszólag bizarr viselkedés az egyik leggyakrabban feltett kérdés azon C++ fejlesztők körében, akik először kutatnak a memória belsejébe, és a válasz egy lenyűgöző utazásra vezet a kód és a tényleges hardver között elhelyezkedő rétegeken keresztül.
Mi történik, ha újat hív
A 72 KB-os adat megértéséhez nyomon kell követnie a teljes kiosztási láncot. Amikor a C++ kód végrehajtja az új int parancsot, a fordító ezt a new operátor hívására fordítja, amely a legtöbb Linux rendszeren átadja a malloc-ot a glibc-ből. De a malloc nem kér közvetlenül a kerneltől 4 bájt memóriát. A kernel lapokban működik – jellemzően 4 KB x86_64-en –, és egy rendszerhívás költsége óriási az egyszerű memória-hozzáféréshez képest. A brk() vagy mmap() meghívása minden egyes kiosztáshoz minden nem triviális programot leállítana.
Ehelyett a glibc memóriaelosztója – a ptmalloc2 nevű implementáció, amely maga Doug Lea klasszikus dlmalloc-jából származik – közvetítőként működik. Előzetesen nagy memóriablokkokat kér a kerneltől, majd kisebb darabokra faragja őket, ahogy a programodnak szüksége van rájuk. Ez az alapvető oka annak, hogy az első 4 bájtos kiosztás sokkal nagyobb kérést indít el az operációs rendszer felé. Az elosztó nem pazarol. Ez stratégiai jellegű.
A 72 KB boncolgatása: Hova mennek a bájtok
A kezdeti lefoglalási többlet több különálló összetevőből származik, amelyeket a futási környezetnek inicializálnia kell, mielőtt akár egyetlen bájt használható memóriát is átadhatna Önnek. Az egyes összetevők megértése megmagyarázza, hogy a szám miért kerül oda, ahol.
💡 DID YOU KNOW?
Mewayz replaces 8+ business tools in one platform
CRM · Invoicing · HR · Projects · Booking · eCommerce · POS · Analytics. Free forever plan available.
Start Free →Először is, a glibc malloc-ja inicializálja a fő arénát – az elsődleges könyvelési struktúrát, amely nyomon követi a főszálon lévő összes allokációt. Ez az aréna tartalmazza a kupac metaadatait, a szabad listás mutatókat és a különböző kiosztási méretekhez tartozó társzerkezeteket. Az allokátor meghosszabbítja a programtörést az sbrk() segítségével, és a kezdeti kiterjesztést az M_TOP_PAD nevű belső paraméter szabályozza, amely alapértelmezés szerint 128 KB kitöltés. A tényleges kezdeti kérés azonban az oldaligazításhoz és a meglévő töréspozícióhoz igazodik, ami gyakran kisebb első kérést eredményez – általában a 72 KB-os érték közelében landol egy frissen indított folyamat során.
Másodszor, a glibc 2.26 óta az allokátor az első használatkor inicializál egy szál helyi gyorsítótárat (tcache). A tcache 64 tárolót tartalmaz (egy kis kiosztású méretosztályonként), amelyek mindegyike legfeljebb 7 gyorsítótárban tárolt darab tárolására képes. Maga a tcache_perthread_struct körülbelül 1 KB-ot fogyaszt, de az inicializálása elindítja a szélesebb aréna beállítását. Harmadszor, a C++ futtatókörnyezet már végrehajtott lefoglalásokat, mielőtt a main() még lefutna – a statikus konstruktorok, az iostream puffer inicializálása az std::cout és a friends számára, valamint a területi beállítások mind hozzájárulnak ehhez a kezdeti halom lábnyomhoz.
Az arénarendszer és miért okos az előzetes kiosztás?
Az a döntés, hogy előre lefoglalunk egy jelentős memóriadarabot ahelyett, hogy részenként kérnénk le, nem véletlen a megvalósítás. Ez egy szándékos mérnöki kompromisszum, amely több évtizedes rendszerprogramozási tapasztalatban gyökerezik. A brk() vagy mmap() minden hívása magában foglalja a felhasználói területről a kernelterületre való kontextusváltást, a folyamat virtuális memória-leképezéseinek módosítását és az oldaltábla esetleges frissítéseit. A modern hardvereken egyetlen rendszerhívás nagyjából 100-200 nanomásodpercbe kerül – önmagában véve triviális, méreteiben katasztrofális.
Vegyünk egy olyan programot, amely 10 000 kis kiosztást végez az inicializálás során. Előzetes kiosztás nélkül ez 10 000 rendszerhívást jelentene, ami hozzávetőlegesen 1-2 milliszekundum tiszta többletköltséget jelent. Aréna alapú allokátorral az első kiosztás trigg
Build Your Business OS Today
From freelancers to agencies, Mewayz powers 138,000+ businesses with 208 integrated modules. Start free, upgrade when you grow.
Create Free Account →Related Posts
- HN megjelenítése: Sgai – Célvezérelt többügynök szoftverfejlesztő (GOAL.md → működő kód)
- Osaka: A Kansai repülőtér büszke arra, hogy soha egyetlen csomagot sem veszített el (2024)
- Túlzott mértékű tokenhasználat a Claude Code-ban
- A kardiorespiratorikus fitnesz alacsonyabb haraggal és szorongással jár