A memória felosztása
Kis áttekintés¶
Ahhoz, hogy jobban megértsük, az egyes adatokat fizikailag hogyan is tárolja a programunk, és miért és hogyan tudunk adott esetben optimálisabb kódot írni C-ben, ha az adatokkal ügyesen bánunk, meg kell ismerjük azt, hogy egy program hogyan foglal helyet a memóriában.
Memória felépítése¶
Az alábbi kép mutatja, hogyan épül fel általánosságban egy C program memóriája. x86-on a verem (stack) a magasabb memóriacímek felől nő az alacsonyabb címek felé (ahogy az ábra is mutatja), ám ez nem szabvány, más architektúrákon fordítva lehet.

A memóriaterületekről néhány szó:
- A stacken (veremben) tárolódik egy-egy függvényhívás adata, vagyis (egyebek mellett) a lokális változók, a függvényeknek átadott paraméterek. A felszabadítás automatikusan, a meghívott függvényből való visszatéréskor megtörténik (emiatt veszélyes egy függvény lokális változójának memóriacímét visszaadni, hiszen az a terület automatikusan felszabadul).
- A heap-en/dinamikus memóriában tárolódik mindaz, amit dinamikusan (
new,malloc,calloc, ...) foglaltunk le. A heap általában az alacsonyabb címek felől növekszik a magasabb címek felé. Ennek felszabadítása nem automatikus, a programozónak kell nem elfelejtenie (delete,free). Ezt a memóriaterületet használják a dinamikusan betöltött library-k is. Elérése költségesebb, mint verem esetén, de a mérete nagyobb, illetve átméretezhető. - BSS (Block Started by Symbol, Uninitalized Data Segment): olyan globális és statikus változók kerülnek ide, amelyeket a programozó nem inicializált saját maga, ezért a program indulásakor automatikusan 0 értéket kapnak. Például a globális változók vagy a függvények
statickulcsszóval ellátott változói. - DS (Initalized Data Segment): olyan globális és statikus változók, amiket a programozó ellátott kezdőértékkel.
- Text: a programból készült gépi utasítások helye.
- Environment: parancssori argumentumok, környezeti változók helye.
A memóriának ezeket a területeit szegmenseknek nevezzük. Minden szegmens meghatározott szabályokkal rendelkezik. Például, hogy az adott szegmens adatai írhatóak-e, vagy sem! Ha az adott szegmens szabályait megsértjük, kapjuk az úgynevezett szegmentálási hibát, vagy segfaultot, ami a programok talán leggyakoribb abortálását okozza.
Tip
A size programot ha alkalmazzuk a binárisra, amit futtatunk, megtudhatjuk, hogy az egyes szegmensekre mekkora terület jut.
Változók és memória¶
A számítógép fenti memória modelljét ezután úgy képzeljük el, mintha rekeszekre bontanánk, ahol minden egyes rekesz 1 byte adatot képes tárolni. (Tulajdonképpen a C-ben mind a kód részre, mind az adat részre tudunk így tekinteni.) Minden rekeszhez egy egyedi sorszám tartozik, amit memóriacímnek hívunk. Ez a cím határozza meg, hogy egy adott adat pontosan hol található a memóriában.
Amikor egy adott típusú változót használunk a programban, akkor valójában azt mondjuk meg, hogy a memóriának egy hány bájtból álló darabját szeretnénk használni. (A változó egyéb jellemzői, illetve létrehozásának módja megadja, hogy mely memória szegmensben kerül tárolásra.) Például egy int típusú változó általában 4 byte-on tárolódik, tehát négy egymás melletti memóriacímre lesz szükség.
A változók memóriában való tárolása tehát két fontos információn alapszik:
- a kezdőcím (az első byte címe, ahol az adat tárolódik),
- és az adattípus mérete (hány byte-on terül el az adat).
Ez alapján a fordítóprogram pontosan tudja, hogy hogyan értelmezze az adott memóriaterület tartalmát – vagyis hogyan olvassa ki vagy módosítsa az ott tárolt értéket.
Tegyük fel, hogy ezt írjuk a programba:
1 | |
Ez mit jelent a memóriában?
- A
xnevű változónk int típusú, tehát (a legtöbb rendszeren) 4 byte-ot foglal. - A fordító lefoglal neki egy szabad memóriaterületet (például a
0x1000címről kezdődően). - A változó értékét, azaz a 5-öt bináris formában eltárolja ezen a 4 byte-os memóriaterületen.
Memóriakép:¶
1 2 3 4 5 6 | |
(Tegyük fel, hogy kis endian a rendszer, vagyis a legkisebb helyiérték kerül a legkisebb címre.)
Magyarázat:¶
- A
5decimális szám binárisan:0000 0000 0000 0000 0000 0000 0000 0101 - Ez hexadecimálisan:
0x00000005 - Ez a 4 byte a
0x1000címtől kezdve fordított sorrendben kerül tárolásra a kis endian miatt: 0x1000: 0x05 (legalacsonyabb byte)0x1001: 0x000x1002: 0x000x1003: 0x00