Gerçekten sisteme bağlıdır, ancak sanal belleğe sahip modern işletim sistemleri , işlem görüntülerini yükleme ve belleği böyle bir şey tahsis etme eğilimindedir:
+---------+
| stack | function-local variables, return addresses, return values, etc.
| | often grows downward, commonly accessed via "push" and "pop" (but can be
| | accessed randomly, as well; disassemble a program to see)
+---------+
| shared | mapped shared libraries (C libraries, math libs, etc.)
| libs |
+---------+
| hole | unused memory allocated between the heap and stack "chunks", spans the
| | difference between your max and min memory, minus the other totals
+---------+
| heap | dynamic, random-access storage, allocated with 'malloc' and the like.
+---------+
| bss | Uninitialized global variables; must be in read-write memory area
+---------+
| data | data segment, for globals and static variables that are initialized
| | (can further be split up into read-only and read-write areas, with
| | read-only areas being stored elsewhere in ROM on some systems)
+---------+
| text | program code, this is the actual executable code that is running.
+---------+
Bu, birçok yaygın sanal bellek sisteminde genel işlem adres alanıdır. "Delik", toplam belleğinizin boyutu, diğer tüm alanların kapladığı alan eksi; bu, yığının büyümesi için geniş bir alan sağlar. Bu aynı zamanda "sanal" dır, yani bir çeviri tablosu aracılığıyla gerçek belleğinizle eşleşir ve gerçek bellekte herhangi bir yerde saklanabilir. Bu şekilde, bir işlemin başka bir işlemin belleğine erişmesini önlemek ve her işlemin tam bir sistemde çalıştığını düşünmesini sağlamak için yapılır.
Yığın ve yığının konumlarının bazı sistemlerde farklı bir sırada olabileceğini unutmayın (bkz. Win32 hakkında daha fazla ayrıntı için aşağıdaki Billy O'Neal'ın cevabına bakın).
Diğer sistemler çok farklı olabilir. Örneğin, DOS gerçek modda koştu ve programları çalıştırırken bellek ayırması çok farklı görünüyordu:
+-----------+ top of memory
| extended | above the high memory area, and up to your total memory; needed drivers to
| | be able to access it.
+-----------+ 0x110000
| high | just over 1MB->1MB+64KB, used by 286s and above.
+-----------+ 0x100000
| upper | upper memory area, from 640kb->1MB, had mapped memory for video devices, the
| | DOS "transient" area, etc. some was often free, and could be used for drivers
+-----------+ 0xA0000
| USER PROC | user process address space, from the end of DOS up to 640KB
+-----------+
|command.com| DOS command interpreter
+-----------+
| DOS | DOS permanent area, kept as small as possible, provided routines for display,
| kernel | *basic* hardware access, etc.
+-----------+ 0x600
| BIOS data | BIOS data area, contained simple hardware descriptions, etc.
+-----------+ 0x400
| interrupt | the interrupt vector table, starting from 0 and going to 1k, contained
| vector | the addresses of routines called when interrupts occurred. e.g.
| table | interrupt 0x21 checked the address at 0x21*4 and far-jumped to that
| | location to service the interrupt.
+-----------+ 0x0
DOS'un işletim sistemi belleğine doğrudan erişime izin verdiğini, herhangi bir koruma olmadan görebildiğini görebilirsiniz;
Bununla birlikte, işlem adres alanında programlar benzer görünme eğilimindeydi, sadece kod segmenti, veri segmenti, yığın, yığın segmenti vb. Olarak tanımlandılar ve biraz farklı bir şekilde haritalandılar. Ancak genel alanların çoğu hala oradaydı.
Programı ve gerekli paylaşılan kütüphaneleri belleğe yükledikten ve programın parçalarını doğru alanlara dağıttıktan sonra, işletim sistemi ana yönteminin bulunduğu her yerde işleminizi yürütmeye başlar ve programınız oradan devralır ve gerektiğinde sistem çağrıları yapar onlara ihtiyacı var.
Farklı sistemler (gömülü, her neyse), istifsiz sistemler, Harvard mimari sistemleri (kod ve veriler ayrı fiziksel bellekte tutulur), aslında BSS'yi salt okunur bellekte tutan (başlangıçta Ancak bu genel özür.
Dedin:
Ayrıca bir bilgisayar programının iki tür bellek kullandığını biliyorum: yığın ve yığın, ayrıca bilgisayarın birincil belleğinin bir parçasıdır.
"Yığın" ve "yığın" fiziksel olarak farklı bellek türleri yerine zorunlu olarak soyut kavramlardır.
Bir yığın sadece bir son giren ilk çıkar veri yapısıdır. X86 mimarisinde, aslında bir ofset kullanılarak uçtan rastgele adreslenebilir, ancak en yaygın işlevler sırasıyla öğeleri eklemek ve çıkarmak için PUSH ve POP'dur. Genellikle işlev yerel değişkenleri ("otomatik depolama" olarak adlandırılır), işlev bağımsız değişkenleri, dönüş adresleri vb. İçin kullanılır (daha fazlası aşağıdadır)
Bir "yığın" sadece talep üzerine tahsis edilebilir belleğin bir yığın için bir takma ad olduğunu ve (Doğrudan herhangi bir konuma erişebilir, anlam) rastgele ele alınmaktadır. Genellikle çalışma zamanında ayırdığınız veri yapıları için kullanılır (C ++ 'da new
ve delete
vemalloc
C ve arkadaşlarınız vb.).
X86 mimarisindeki yığın ve yığın, fiziksel olarak sistem belleğinizde (RAM) bulunur ve sanal bellek ayırma yoluyla yukarıda açıklandığı gibi işlem adres alanına eşlenir.
Kayıt (hala x 86) İşlemci talimatlara bağlı olarak, fiziksel olarak işlemci (RAM aksine) içinde bulunan ve metin alanı, işlemci tarafından yüklenir (ve aynı zamanda bellek veya diğer yerlerde başka yüklenebilir bu aslında yürütülür). Aslında, çok farklı amaçlar için kullanılan çok küçük, çok hızlı çip üzeri bellek konumlarıdır.
Kayıt düzeni, mimariye oldukça bağımlıdır (aslında, kayıtlar, komut seti ve bellek düzeni / tasarımı, "mimari" ile kastedilen şeydir) ve bu yüzden üzerine genişlemeyeceğim, ancak bir montaj dil kursu daha iyi anlamak için.
Senin sorun:
Yığın talimatların yürütülmesi için hangi noktada kullanılır? Talimatlar RAM'den, yığına, kayıtlara mı gidiyor?
Yığın (bunları kullanan ve kullanan sistemlerde / dillerde) çoğunlukla şu şekilde kullanılır:
int mul( int x, int y ) {
return x * y; // this stores the result of MULtiplying the two variables
// from the stack into the return value address previously
// allocated, then issues a RET, which resets the stack frame
// based on the arg list, and returns to the address set by
// the CALLer.
}
int main() {
int x = 2, y = 3; // these variables are stored on the stack
mul( x, y ); // this pushes y onto the stack, then x, then a return address,
// allocates space on the stack for a return value,
// then issues an assembly CALL instruction.
}
Bunun gibi basit bir program yazın ve ardından derlemeye ( gcc -S foo.c
GCC'ye erişiminiz varsa) derleyin ve bir göz atın. Montajı takip etmek oldukça kolaydır. Yığın, işlev yerel değişkenleri ve işlevleri çağırmak için argümanlarını ve dönüş değerlerini saklamak için kullanıldığını görebilirsiniz. Bu yüzden böyle bir şey yaptığınızda:
f( g( h( i ) ) );
Bunların hepsi sırayla çağrılır. Kelimenin tam anlamıyla bir işlev çağrıları ve argümanları yığını oluşturur, bunları yürütür ve sonra geri sarıldığında (veya yukarı;) patlar. Bununla birlikte, yukarıda belirtildiği gibi, yığın (x86'da) aslında işlem bellek alanınızda (sanal bellekte) bulunur ve bu nedenle doğrudan manipüle edilebilir; yürütme sırasında ayrı bir adım değildir (veya en azından sürece diktir).
FYI, yukarıdaki C ++ tarafından da kullanılan C çağırma kuralıdır . Diğer diller / sistemler, bağımsız değişkenleri yığına farklı bir sırayla aktarabilir ve bazı diller / platformlar yığınlar bile kullanmaz ve farklı şekillerde devam eder.
Ayrıca, bunların gerçek C kodu yürütme satırları olmadığını unutmayın. Derleyici bunları yürütülebilir dosyadaki makine dili yönergelerine dönüştürdü. Daha sonra (genellikle) METİN alanından CPU boru hattına, daha sonra CPU kayıtlarına kopyalanır ve oradan yürütülür. [Bu yanlıştı. Aşağıdaki Ben Voigt düzeltmesine bakın.]