Was passiert, wenn ein Computerprogramm ausgeführt wird?

180

Ich kenne die allgemeine Theorie, aber ich kann nicht in die Details passen.

Ich weiß, dass sich ein Programm im Sekundärspeicher eines Computers befindet. Sobald das Programm mit der Ausführung beginnt, wird es vollständig in den RAM kopiert. Dann ruft der Prozessor jeweils einige Anweisungen ab (dies hängt von der Größe des Busses ab), legt sie in Register und führt sie aus.

Ich weiß auch, dass ein Computerprogramm zwei Arten von Speicher verwendet: Stapel und Heap, die ebenfalls Teil des Primärspeichers des Computers sind. Der Stapel wird für nicht dynamischen Speicher und der Heap für dynamischen Speicher verwendet (z. B. alles, was mit dem newOperator in C ++ zusammenhängt).

Was ich nicht verstehen kann, ist, wie diese beiden Dinge sich verbinden. Ab wann wird der Stack für die Ausführung der Anweisungen verwendet? Anweisungen gehen vom RAM zum Stapel, zu den Registern?

Gaijinco
quelle
43
+1 für eine grundlegende Frage!
mkelley33
21
hmm ... weißt du, sie schreiben Bücher darüber. Möchten Sie diesen Teil der Betriebssystemarchitektur wirklich mit Hilfe von SO studieren?
Andrey
1
Ich habe ein paar Tags hinzugefügt, die auf dem speicherbezogenen Charakter der Frage und dem Verweis auf C ++ basieren, obwohl ich denke, dass eine gute Antwort auch von jemandem kommen könnte, der sich mit Java oder C #
auskennt
14
Upvoted und favorisiert. Ich hatte immer zu viel Angst zu fragen ...
Maxpm
2
Der Begriff "legt sie in Register" ist nicht ganz richtig. Auf den meisten Prozessoren werden Register verwendet, um Zwischenwerte und keinen ausführbaren Code zu speichern.

Antworten:

161

Es hängt wirklich vom System ab, aber moderne Betriebssysteme mit virtuellem Speicher neigen dazu, ihre Prozessabbilder zu laden und Speicher wie folgt zuzuweisen:

+---------+
|  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.
+---------+

Dies ist der allgemeine Prozessadressraum auf vielen gängigen virtuellen Speichersystemen. Das "Loch" ist die Größe Ihres gesamten Speichers abzüglich des von allen anderen Bereichen belegten Speicherplatzes. Dies gibt dem Haufen viel Platz, in den er hineinwachsen kann. Dies ist auch "virtuell", dh es wird über eine Übersetzungstabelle Ihrem tatsächlichen Speicher zugeordnet und kann tatsächlich an einer beliebigen Stelle im tatsächlichen Speicher gespeichert werden. Auf diese Weise wird ein Prozess vor dem Zugriff auf den Speicher eines anderen Prozesses geschützt und jeder Prozess wird davon ausgegangen, dass er auf einem vollständigen System ausgeführt wird.

Beachten Sie, dass die Positionen von z. B. Stapel und Heap auf einigen Systemen möglicherweise in einer anderen Reihenfolge liegen ( weitere Informationen zu Win32 finden Sie in der Antwort von Billy O'Neal unten).

Andere Systeme können sehr unterschiedlich sein. DOS wurde beispielsweise im Real-Modus ausgeführt , und die Speicherzuweisung beim Ausführen von Programmen sah ganz anders aus:

+-----------+ 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

Sie können sehen, dass DOS den direkten Zugriff auf den Betriebssystemspeicher ohne Schutz ermöglichte, was bedeutete, dass User-Space-Programme im Allgemeinen direkt auf alles zugreifen oder es überschreiben konnten, was ihnen gefiel.

Im Prozessadressraum sahen die Programme jedoch in der Regel ähnlich aus, nur wurden sie als Codesegment, Datensegment, Heap, Stapelsegment usw. beschrieben und etwas anders zugeordnet. Aber die meisten allgemeinen Bereiche waren noch da.

Nachdem das Programm und die erforderlichen gemeinsam genutzten Bibliotheken in den Speicher geladen und die Teile des Programms in die richtigen Bereiche verteilt wurden, beginnt das Betriebssystem mit der Ausführung Ihres Prozesses, wo immer sich seine Hauptmethode befindet, und Ihr Programm übernimmt von dort aus und führt bei Bedarf Systemaufrufe durch es braucht sie.

Verschiedene Systeme (eingebettet, was auch immer) können sehr unterschiedliche Architekturen aufweisen, wie z. B. stapellose Systeme, Harvard-Architektursysteme (wobei Code und Daten in einem separaten physischen Speicher gespeichert werden), Systeme, die das BSS tatsächlich im Nur-Lese-Speicher halten (ursprünglich von der Programmierer) usw. Aber das ist der allgemeine Kern.


Du sagtest:

Ich weiß auch, dass ein Computerprogramm zwei Arten von Speicher verwendet: Stapel und Heap, die ebenfalls Teil des Primärspeichers des Computers sind.

"Stapel" und "Haufen" sind nur abstrakte Konzepte und keine (notwendigerweise) physikalisch unterschiedlichen "Arten" von Erinnerungen.

Ein Stack ist lediglich eine Last-In-First-Out-Datenstruktur. In der x86-Architektur kann es tatsächlich zufällig adressiert werden, indem ein Versatz vom Ende verwendet wird. Die häufigsten Funktionen sind jedoch PUSH und POP zum Hinzufügen bzw. Entfernen von Elementen. Es wird häufig für funktionslokale Variablen (sogenannte "automatische Speicherung"), Funktionsargumente, Rücksprungadressen usw. verwendet (mehr unten).

Ein "Heap" ist nur ein Spitzname für einen Speicherblock, der bei Bedarf zugewiesen werden kann und zufällig adressiert wird (dh Sie können direkt auf einen beliebigen Speicherort zugreifen). Es wird häufig für Datenstrukturen verwendet, die Sie zur Laufzeit zuweisen (in C ++, Verwenden von newund deleteund mallocund Freunde in C usw.).

Der Stapel und der Heap in der x86-Architektur befinden sich beide physisch in Ihrem Systemspeicher (RAM) und werden wie oben beschrieben durch Zuweisung des virtuellen Speichers in den Prozessadressraum abgebildet.

Die Register (immer noch auf x86) befinden sich physisch im Prozessor (im Gegensatz zum RAM) und werden vom Prozessor aus dem TEXT-Bereich geladen (und können abhängig von den CPU-Anweisungen auch von einer anderen Stelle im Speicher oder an anderen Stellen geladen werden) tatsächlich ausgeführt werden). Es handelt sich im Wesentlichen nur um sehr kleine, sehr schnelle Speicherplätze auf dem Chip, die für verschiedene Zwecke verwendet werden.

Das Registerlayout hängt stark von der Architektur ab (tatsächlich sind die Register, der Befehlssatz und das Speicherlayout / -design genau das, was unter "Architektur" zu verstehen ist), und daher werde ich nicht darauf eingehen, sondern Ihnen empfehlen, eine zu verwenden Assembler-Kurs, um sie besser zu verstehen.


Ihre Frage:

Ab wann wird der Stack für die Ausführung der Anweisungen verwendet? Anweisungen gehen vom RAM zum Stapel, zu den Registern?

Der Stapel (in Systemen / Sprachen, die sie haben und verwenden) wird am häufigsten wie folgt verwendet:

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.
}

Schreiben Sie ein einfaches Programm wie dieses, kompilieren Sie es dann zu Assembly ( gcc -S foo.cwenn Sie Zugriff auf GCC haben) und werfen Sie einen Blick darauf. Die Montage ist ziemlich einfach zu verfolgen. Sie können sehen, dass der Stapel für lokale Funktionsvariablen und zum Aufrufen von Funktionen, Speichern ihrer Argumente und Rückgabewerte verwendet wird. Dies ist auch der Grund, warum Sie etwas tun wie:

f( g( h( i ) ) ); 

All dies wird nacheinander aufgerufen. Es baut buchstäblich einen Stapel von Funktionsaufrufen und deren Argumenten auf, führt sie aus und löscht sie dann, wenn sie sich wieder nach unten (oder oben) drehen. Wie oben erwähnt, befindet sich der Stapel (auf x86) jedoch tatsächlich in Ihrem Prozessspeicher (im virtuellen Speicher) und kann daher direkt bearbeitet werden. Dies ist kein separater Schritt während der Ausführung (oder zumindest orthogonal zum Prozess).

Zu Ihrer Information, das Obige ist die C-Aufrufkonvention , die auch von C ++ verwendet wird. Andere Sprachen / Systeme können Argumente in einer anderen Reihenfolge auf den Stapel übertragen, und einige Sprachen / Plattformen verwenden nicht einmal Stapel und gehen auf unterschiedliche Weise vor.

Beachten Sie auch, dass dies keine tatsächlichen Zeilen der Ausführung von C-Code sind. Der Compiler hat sie in maschinensprachliche Anweisungen in Ihrer ausführbaren Datei konvertiert. Sie werden dann (allgemein) aus dem TEXT-Bereich in die CPU-Pipeline, dann in die CPU-Register kopiert und von dort ausgeführt. [Das war falsch. Siehe Ben Voigts Korrektur unten.]

Sdaz MacSkibbons
quelle
4
Entschuldigung, aber eine gute Buchempfehlung wäre eine bessere Antwort, IMO
Andrey
13
Ja, "RTFM" ist immer besser.
Sdaz MacSkibbons
56
@Andrey: Vielleicht sollten Sie diesen Kommentar in "auch, vielleicht möchten Sie Ihre Empfehlung für ein gutes Buch lesen" ändern. Ich verstehe, dass diese Art von Frage mehr Nachforschungen verdient , aber wann immer Sie einen Kommentar mit "Entschuldigung, aber" beginnen müssen. .. "Vielleicht sollten Sie wirklich in Betracht ziehen, den Beitrag für die Aufmerksamkeit des Moderators zu markieren oder zumindest eine Erklärung dafür abzugeben , warum Ihre Meinung sowieso für irgendjemanden von Bedeutung sein sollte.
mkelley33
2
Hervorragende Antwort. Es hat sicherlich einige Dinge für mich geklärt!
Maxpm
2
@Mikael: Abhängig von der Implementierung kann das Caching obligatorisch sein. In diesem Fall wird jedes Mal, wenn Daten aus dem Speicher gelesen werden, eine gesamte Cache-Zeile gelesen und der Cache gefüllt. Oder es kann möglich sein, dem Cache-Manager einen Hinweis zu geben, dass die Daten nur einmal benötigt werden, sodass das Kopieren in den Cache nicht hilfreich ist. Das ist zum Lesen. Zum Schreiben gibt es Rückschreib- und Durchschreibcaches, die sich darauf auswirken, wann DMA-Controller die Daten lesen können, und dann gibt es eine ganze Reihe von Cache-Kohärenzprotokollen für den Umgang mit mehreren Prozessoren, die jeweils einen eigenen Cache haben. Dies verdient wirklich sein eigenes Q.
Ben Voigt
61

Sdaz hat in sehr kurzer Zeit eine bemerkenswerte Anzahl von Upvotes erhalten, setzt aber leider ein Missverständnis darüber fort, wie sich Anweisungen durch die CPU bewegen.

Die Frage stellte:

Anweisungen gehen vom RAM zum Stapel, zu den Registern?

Sdaz sagte:

Beachten Sie auch, dass dies keine tatsächlichen Zeilen der Ausführung von C-Code sind. Der Compiler hat sie in maschinensprachliche Anweisungen in Ihrer ausführbaren Datei konvertiert. Sie werden dann (allgemein) aus dem TEXT-Bereich in die CPU-Pipeline, dann in die CPU-Register kopiert und von dort ausgeführt.

Das ist aber falsch. Mit Ausnahme des Sonderfalls des selbstmodifizierenden Codes werden Anweisungen niemals in den Datenpfad eingegeben. Und sie werden nicht vom Datenpfad ausgeführt.

Die x86-CPU-Register sind:

  • Allgemeine Register EAX EBX ECX EDX

  • Segmentregister CS DS ES FS GS SS

  • Index und Zeiger ESI EDI EBP EIP ESP

  • Indikator EFLAGS

Es gibt auch einige Gleitkomma- und SIMD-Register, aber für die Zwecke dieser Diskussion werden wir diese als Teil des Coprozessors und nicht der CPU klassifizieren. Die Speicherverwaltungseinheit in der CPU hat auch einige eigene Register. Wir werden dies wiederum als separate Verarbeitungseinheit behandeln.

Keines dieser Register wird für ausführbaren Code verwendet. EIPenthält die Adresse der ausführenden Anweisung, nicht die Anweisung selbst.

Anweisungen durchlaufen in der CPU einen völlig anderen Pfad als Daten (Harvard-Architektur). Alle aktuellen Maschinen sind Harvard-Architekturen innerhalb der CPU. Die meisten dieser Tage sind auch Harvard-Architektur im Cache. x86 (Ihr üblicher Desktop-Computer) ist eine Von-Neumann-Architektur im Hauptspeicher, dh Daten und Code werden im RAM vermischt. Das ist nebensächlich, da wir darüber sprechen, was in der CPU passiert.

Die klassische Sequenz, die in der Computerarchitektur gelehrt wird, ist Fetch-Decode-Execute. Der Speichercontroller schlägt den unter der Adresse gespeicherten Befehl nach EIP. Die Bits des Befehls durchlaufen eine kombinatorische Logik, um alle Steuersignale für die verschiedenen Multiplexer im Prozessor zu erzeugen. Und nach einigen Zyklen gelangt die arithmetische Logikeinheit zu einem Ergebnis, das in das Ziel getaktet wird. Dann wird die nächste Anweisung abgerufen.

Bei einem modernen Prozessor sieht es etwas anders aus. Jeder eingehende Befehl wird in eine ganze Reihe von Mikrocode-Befehlen übersetzt. Dies ermöglicht das Pipelining, da die vom ersten Mikrobefehl verwendeten Ressourcen später nicht benötigt werden, sodass sie ab dem nächsten Befehl mit der Arbeit am ersten Mikrobefehl beginnen können.

Um das Ganze abzurunden, ist die Terminologie leicht verwirrt, da Register ein elektrotechnischer Begriff für eine Sammlung von D-Flipflops ist. Und Anweisungen (oder insbesondere Mikroanweisungen) können sehr gut vorübergehend in einer solchen Sammlung von D-Flipflops gespeichert werden. Dies ist jedoch nicht gemeint, wenn ein Informatiker, Softwareentwickler oder gewöhnlicher Entwickler den Begriff Register verwendet . Sie bedeuten die oben aufgeführten Datenpfadregister, die nicht zum Transport von Code verwendet werden.

Die Namen und die Anzahl der Datenpfadregister variieren für andere CPU-Architekturen wie ARM, MIPS, Alpha, PowerPC, aber alle führen Anweisungen aus, ohne sie durch die ALU zu leiten.

Ben Voigt
quelle
Danke für die Klarstellung. Ich zögerte, das hinzuzufügen, da ich nicht sehr vertraut damit bin, es aber auf Wunsch eines anderen tat.
Sdaz MacSkibbons
s / ARM / RAM / in "bedeutet, dass Daten und Code in ARM vermischt sind". Richtig?
Bjarke Freund-Hansen
@bjarkef: Das erste Mal ja, aber nicht das zweite Mal. Ich werde es reparieren.
Ben Voigt
17

Das genaue Layout des Speichers während der Ausführung eines Prozesses hängt vollständig von der Plattform ab, die Sie verwenden. Betrachten Sie das folgende Testprogramm:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    int stackValue = 0;
    int *addressOnStack = &stackValue;
    int *addressOnHeap = malloc(sizeof(int));
    if (addressOnStack > addressOnHeap)
    {
        puts("The stack is above the heap.");
    }
    else
    {
        puts("The heap is above the stack.");
    }
}

Unter Windows NT (und seinen Kindern) wird dieses Programm im Allgemeinen Folgendes produzieren:

Der Haufen befindet sich über dem Stapel

Auf POSIX-Boxen heißt es:

Der Stapel befindet sich über dem Haufen

Das UNIX-Speichermodell wird hier von @Sdaz MacSkibbons recht gut erklärt, daher werde ich das hier nicht wiederholen. Dies ist jedoch nicht das einzige Speichermodell. Der Grund, warum POSIX dieses Modell benötigt, ist der sbrk -Systemaufruf. Grundsätzlich weist ein Prozess auf einer POSIX-Box den Kernel lediglich an, den Teiler zwischen dem "Loch" und dem "Heap" weiter in den Bereich "Loch" zu verschieben, um mehr Speicher zu erhalten. Es gibt keine Möglichkeit, Speicher an das Betriebssystem zurückzugeben, und das Betriebssystem selbst verwaltet Ihren Heap nicht. Ihre C-Laufzeitbibliothek muss dies bereitstellen (über malloc).

Dies hat auch Auswirkungen auf die Art von Code, der tatsächlich in POSIX-Binärdateien verwendet wird. POSIX-Boxen verwenden (fast universell) das ELF-Dateiformat. In diesem Format ist das Betriebssystem für die Kommunikation zwischen Bibliotheken in verschiedenen ELF-Dateien verantwortlich. Daher verwenden alle Bibliotheken positionsunabhängigen Code (dh der Code selbst kann in verschiedene Speicheradressen geladen werden und weiterhin funktionieren), und alle Aufrufe zwischen Bibliotheken werden durch eine Nachschlagetabelle geleitet, um herauszufinden, wo die Steuerung für cross springen muss Funktionsaufrufe der Bibliothek. Dies erhöht den Overhead und kann ausgenutzt werden, wenn eine der Bibliotheken die Nachschlagetabelle ändert.

Das Speichermodell von Windows ist unterschiedlich, da die Art des verwendeten Codes unterschiedlich ist. Windows verwendet das PE-Dateiformat, bei dem der Code im positionsabhängigen Format verbleibt. Das heißt, der Code hängt davon ab, wo genau im virtuellen Speicher der Code geladen wird. In der PE-Spezifikation befindet sich ein Flag, das dem Betriebssystem mitteilt, wo genau im Speicher die Bibliothek oder ausführbare Datei zugeordnet werden soll, wenn Ihr Programm ausgeführt wird. Wenn ein Programm oder eine Bibliothek nicht an der bevorzugten Adresse geladen werden kann, muss der Windows Loader neu gestartet werdenDie Bibliothek / ausführbare Datei - im Grunde verschiebt sie den positionsabhängigen Code, um auf die neuen Positionen zu zeigen - erfordert keine Nachschlagetabellen und kann nicht ausgenutzt werden, da keine Nachschlagetabelle zum Überschreiben vorhanden ist. Leider erfordert dies eine sehr komplizierte Implementierung im Windows Loader und einen erheblichen Startzeitaufwand, wenn ein Image neu basiert werden muss. Große kommerzielle Softwarepakete ändern ihre Bibliotheken häufig so, dass sie absichtlich an verschiedenen Adressen beginnen, um ein erneutes Basieren zu vermeiden. Windows selbst tut dies mit seinen eigenen Bibliotheken (z. B. ntdll.dll, kernel32.dll, psapi.dll usw. - alle haben standardmäßig unterschiedliche Startadressen).

Unter Windows virtuelle Speicher aus dem System über einen Aufruf erhalten werden VirtualAlloc , und es wird das System über zurückVirtual (Okay, technisch VirtualAlloc Farmen, um NtAllocateVirtualMemory, aber das ist eine Implementierung Detail) ( Man vergleiche dies zu POSIX, wo Speicher können nicht zurückgefordert werden). Dieser Prozess ist langsam (und IIRC erfordert, dass Sie physische Seitenblöcke zuweisen, normalerweise 4 KB oder mehr). Windows bietet auch eigene Heap-Funktionen (HeapAlloc, HeapFree usw.) als Teil einer Bibliothek namens RtlHeap, die als Teil von Windows selbst enthalten ist und auf der mallocnormalerweise die C-Laufzeit (dh Freunde) implementiert ist.

Windows verfügt auch über einige ältere Speicherzuweisungs-APIs aus der Zeit, als es mit alten 80386s zu tun hatte, und diese Funktionen basieren jetzt auf RtlHeap. Weitere Informationen zu den verschiedenen APIs, die die Speicherverwaltung in Windows steuern, finden Sie in diesem MSDN-Artikel: http://msdn.microsoft.com/en-us/library/ms810627 .

Beachten Sie auch, dass dies unter Windows bedeutet, dass ein einzelner Prozess (und normalerweise) mehr als einen Heap hat. (Normalerweise erstellt jede gemeinsam genutzte Bibliothek einen eigenen Heap.)

(Die meisten dieser Informationen stammen aus "Secure Coding in C und C ++" von Robert Seacord.)

Billy ONeal
quelle
Tolle Infos, danke! Hoffe, "user487117" kommt schließlich tatsächlich zurück. :-)
Sdaz MacSkibbons
5

Der Stapel

In der X86-Architektur führt die CPU Operationen mit Registern aus. Der Stapel wird nur aus praktischen Gründen verwendet. Sie können den Inhalt Ihrer Register im Stapel speichern, bevor Sie eine Unterroutine oder eine Systemfunktion aufrufen, und sie dann wieder laden, um den Vorgang dort fortzusetzen, wo Sie ihn verlassen haben. (Sie können es manuell ohne den Stapel tun, aber es ist eine häufig verwendete Funktion, so dass es CPU-Unterstützung hat). Aber Sie können so ziemlich alles ohne den Stapel in einem PC tun.

Zum Beispiel eine ganzzahlige Multiplikation:

MUL BX

Multipliziert das AX-Register mit dem BX-Register. (Das Ergebnis ist in DX und AX, DX enthält die höheren Bits).

Stapelbasierte Maschinen (wie JAVA VM) verwenden den Stapel für ihre grundlegenden Vorgänge. Die obige Multiplikation:

DMUL

Dadurch werden zwei Werte vom oberen Rand des Stapels eingefügt, das Tempo multipliziert und das Ergebnis dann wieder auf den Stapel verschoben. Der Stapel ist für diese Art von Maschinen unerlässlich.

Einige übergeordnete Programmiersprachen (wie C und Pascal) verwenden diese spätere Methode zum Übergeben von Parametern an Funktionen: Die Parameter werden in der Reihenfolge von links nach rechts auf den Stapel verschoben und vom Funktionskörper gepoppt, und die Rückgabewerte werden zurückgeschoben. (Dies ist eine Entscheidung, die die Compilerhersteller treffen und die Art und Weise, wie der X86 den Stack verwendet, missbraucht).

Der Haufen

Der Heap ist ein anderes Konzept, das nur im Bereich der Compiler existiert. Es nimmt Ihnen die Mühe, den Speicher hinter Ihren Variablen zu verwalten, aber es ist keine Funktion der CPU oder des Betriebssystems, sondern nur eine Wahl der Verwaltung des Speicherblocks, der vom Betriebssystem ausgegeben wird. Sie können dies viele Male tun, wenn Sie möchten.

Zugriff auf Systemressourcen

Das Betriebssystem verfügt über eine öffentliche Schnittstelle, über die Sie auf seine Funktionen zugreifen können. In DOS werden Parameter in Registern der CPU übergeben. Windows verwendet den Stapel zum Übergeben von Parametern für Betriebssystemfunktionen (die Windows-API).

vbence
quelle