Hogyan lehet megérteni a program memóriáját

Ha olyan nyelven kódol, mint a C vagy a C ++, akkor alacsonyabb szintű interakcióba léphet a memóriájával. Néha ez sok problémát vet fel, amelyeket korábban nem kapott: szegfaults . Ezek a hibák meglehetősen bosszantóak, és sok bajt okozhatnak. Gyakran jelzik, hogy olyan memóriát használ, amelyet nem szabad használni.

Az egyik leggyakoribb probléma a már felszabadult memória elérése. Ez olyan memória, amelyet vagy kiadott free, vagy memória, amelyet a program automatikusan felszabadított, például a veremből.

Mindezek megértése nagyon egyszerű, és mindenképpen jobb és intelligensebb programozásra készteti.

Hogyan oszlik meg a memória?

A memória több szegmensre oszlik. Ennek a bejegyzésnek a két legfontosabb a verem és a halom . A verem rendezett beillesztési hely, míg a kupac véletlenszerű - a memóriát mindenhol lefoglalja, ahol csak tudja.

A verem memóriának számos módja és művelete van a munkájához. Itt tárolják a processzor regisztrációinak egy részét. És hová kerülnek a programoddal kapcsolatos releváns információk - mely függvényeket hívják meg, milyen változókat hoztál létre, és még néhány további információt. Ezt a memóriát szintén a program kezeli, és nem a fejlesztő.

A halmot gyakran használják nagy memóriamennyiségek kiosztására, amelyek állítólag léteznek, amíg a fejlesztő akarja. Ez azt jelenti, hogy a fejlesztő feladata ellenőrizni a halom memóriájának használatát . Összetett programok készítésekor gyakran nagy memóriarészeket kell kiosztani, és itt használja a kupacot. Ezt dinamikus memóriának hívjuk .

Minden alkalommal a halomra helyezi a dolgokat, amikor mallocvalamire memóriát rendel. Bármely más hívás, amelyik hasonló int i;, verem memória. Ennek ismerete nagyon fontos, hogy könnyen megtalálhassa a hibákat a programjában, és tovább javítsa a Segfault hibakeresését.

A verem megértése

Bár lehet, hogy nem tud róla, a program folyamatosan kiosztja a verem memóriáját a működéséhez. Minden helyi változó és minden hívott funkció oda megy. Ezzel sok mindent megtehet - ezek többnyire olyan dolgok, amelyekre nem akartál sort keríteni -, például a puffer túlcsordulása és a helytelen memória elérése.

Tehát hogyan működik valójában?

A verem egy LIFO (Last-In-First-Out) adatszerkezet. Megtekintheti tökéletesen illeszkedő könyvek dobozaként - az utoljára elhelyezett könyv az első, amelyet kivesz. Ennek a struktúrának a használatával a program könnyen kezelheti az összes műveletet és hatókört két egyszerű művelettel: push és pop .

Ez a kettő pontosan ellentétesen cselekszik egymással. Nyomja meg az értéket a verem tetejére. A pop a felső értéket veszi tőle.

Az aktuális memóriahelyek nyomon követéséhez van egy speciális processzorregiszter, Stack Pointer néven . Minden alkalommal, amikor el kell mentenie valamit - például egy változót vagy egy függvény visszatérési címét -, az felfelé tolja és mozgatja a verem mutatóját. Minden alkalommal, amikor kilép egy funkcióból, a verem mutatójától kezdve mindent a függvény elmentett visszatérési címéig ugrik elő. Ez egyszerű!

Teszteljük, megértettük-e a következő példát (próbáld meg egyedül megtalálni a hibát ☺️):

Ha futtatja, akkor a program egyszerűen szegfault. Miért történik ez? Minden a helyén látszik! Kb. ... a verem kivételével.

Amikor meghívjuk a függvényt createArray, a verem:

  • elmenti a visszatérési címet,
  • létrehoz arra verem memóriájában és visszaadja (egy tömb egyszerűen egy memóriahelyre mutató mutató az információival)
  • de mivel nem használtuk malloc, a verem memóriájába kerül.

Miután visszaküldtük a mutatót, mivel nincs kontrollunk a veremműveletek felett, a program eldobja az információkat a veremből, és szükség szerint felhasználja azokat. Amikor megpróbáljuk kitölteni a tömböt, miután visszatértünk a funkcióból, megrongáltuk a memóriát - ezzel a program szétbomlott.

A halom megértése

A verem ellenében a halom az, amelyet akkor használ, ha azt szeretné, hogy valami létezzen egy ideig a funkcióktól és a hatóköröktől függetlenül. Ennek a memóriának a használatához a C nyelv stdlib nagyon jó, mivel két félelmetes funkciót hoz: mallocés free.

A Malloc (memóriaallokáció) kéri a rendszert a kért memóriamennyiségért, és egy mutatót ad vissza a kiindulási címre. A Free azt mondja a rendszernek, hogy a kért memóriára már nincs szükség, és más feladatokhoz használható. Nagyon egyszerűnek tűnik - mindaddig, amíg elkerüli a hibákat.

A rendszer nem tudja felülírni azt, amit a fejlesztők kértek. Tehát rajtunk, embereken múlik, hogy a fenti két funkcióval kezeljük-e. Ez megnyitja az ajtót egy emberi hibának: a memória kiszivárog.

A memóriaszivárgás a felhasználó által kért memória, amelyet soha nem szabadítottak fel - amikor a program véget ért, vagy a helyére mutató mutatók elvesznek. Ezáltal a program sokkal több memóriát használ fel, mint amire kellett volna. Ennek elkerülése érdekében minden alkalommal, amikor már nincs szükségünk halomra allokált elemre, felszabadítjuk.

A fenti képen a rossz út soha nem szabadítja fel az általunk használt memóriát. Ez végül 20 * 4 bájtot pazarol (int-méret 64 bitesben) = 80 bájt. Lehet, hogy ez nem tűnik annyira, de képzelje el, hogy ezt nem óriási programban tenné meg. Végül gigabájtokat pazarolhatunk!

A halom memória kezelése elengedhetetlen a programok memóriájának hatékonyabbá tétele érdekében. De arra is ügyelnie kell, hogy miként használja. Csakúgy, mint a verem memóriájában, a memória felszabadulása után is annak elérése vagy használata segfaultot okozhat.

Bónusz: Struktúrák és a kupac

A struktúrák használatakor az egyik leggyakoribb hiba a struktúra felszabadítása. Ez rendben van, amíg nem osztottunk memóriát a struktúrán belüli mutatókra. Ha memóriát osztanak ki a struktúrán belüli mutatókra, akkor először meg kell szabadítanunk őket. Ezután felszabadíthatjuk a teljes struktúrát.

Hogyan oldom meg a memóriaszivárgás problémáimat

Legtöbbször, amikor C-ben programozok, struktúrákat használok. Ezért mindig két kötelező funkciót kell használnom a szerkezeteimmel : a konstruktort és a destruktort .

Ez a két funkció az egyetlen, ahol a mallocs-okat használom, és felszabadítom a struktúrát. Ez igazán egyszerűvé és könnyen megoldhatóvá teszi a memóriaszivárgásaimat.

(Ha többet szeretne tudni a kód könnyebb olvashatóságáról, ellenőrizze az absztrakcióról szóló bejegyzésemet).

Remek memóriakezelő eszköz - Valgrind

Nehéz kezelni a memóriát, és megbizonyosodni arról, hogy mindent helyesen kezelt. Remek eszköz a Valgrind ellenőrzésére, ha programja megfelelően viselkedik. Ez az eszköz ellenőrzi a programot, megmondva, hogy mennyi memóriát rendelt el, mennyit szabadított fel, ha helytelen memóriaterületre próbált írni ... Ennek használata nagyszerű módja annak ellenőrzésére, hogy minden rendben van-e, és ezt el kell használnia az elkerülése érdekében biztonsági kompromisszumok.

Ne felejtsd el követni!

A Mediumon való közzététel mellett a Twitteren is vagyok.

Ha bármilyen kérdése vagy javaslata van, ne habozzon kapcsolatba lépni velem.