Abschnitt 2 TClass Atom
In der System.pas-Einheit ist TClass wie folgt definiert:
TClass = Klasse von TObject;
Das bedeutet, dass TClass die Klasse von TObject ist. Da TObject selbst eine Klasse ist, ist TClass die sogenannte Klasse von Klassen.
Konzeptionell ist TClass eine Art Klasse, also eine Klasse. Wir wissen jedoch, dass eine Klasse von DELPHI einen Teil der VMT-Daten darstellt. Daher kann die Klasse als der für das VMT-Datenelement definierte Typ betrachtet werden. Tatsächlich handelt es sich um einen Zeigertyp, der auf die VMT-Daten zeigt!
In der vorherigen traditionellen C++-Sprache konnte der Typ einer Klasse nicht definiert werden. Sobald das Objekt kompiliert ist, ist es fixiert, die Strukturinformationen der Klasse wurden in absoluten Maschinencode umgewandelt und die vollständigen Klasseninformationen sind nicht im Speicher vorhanden. Einige objektorientierte Sprachen höherer Ebenen können den dynamischen Zugriff und Aufruf von Klasseninformationen unterstützen, erfordern jedoch häufig einen komplexen internen Interpretationsmechanismus und mehr Systemressourcen. Die Object Pascal-Sprache von DELPHI übernimmt einige der hervorragenden Funktionen objektorientierter Hochsprachensprachen und behält gleichzeitig den traditionellen Vorteil der direkten Kompilierung von Programmen in Maschinencode bei, wodurch die Probleme erweiterter Funktionen und Programmeffizienz perfekt gelöst werden.
Gerade weil DELPHI vollständige Klasseninformationen in der Anwendung behält, kann es erweiterte objektorientierte Funktionen bereitstellen, wie z. B. das Konvertieren und Identifizieren von Klassen zur Laufzeit, wobei die VMT-Daten der Klasse eine Schlüsselrolle spielen. Interessierte Freunde können die beiden Assemblerprozesse von AsClass und IsClass in der Systemeinheit lesen. Sie sind die Implementierungscodes der as- und is-Operatoren, um ihr Verständnis von Klassen und VMT-Daten zu vertiefen.
Mit dem Klassentyp können Sie die Klasse als Variable verwenden. Eine Klassenvariable kann als spezielles Objekt verstanden werden, und Sie können auf die Methoden einer Klassenvariablen wie auf ein Objekt zugreifen. Schauen wir uns zum Beispiel das folgende Programmfragment an:
Typ
TSampleClass = Klasse von TSampleObject;
TSampleObject = Klasse( TObject )
öffentlich
Konstruktor Erstellen;
Destruktor Zerstören; überschreiben;
Klassenfunktion GetSampleObjectCount:Integer;
PROzedur GetObjectIndex:Integer;
Ende;
var
aSampleClass : TSampleClass;
aClass: TClass;
In diesem Code definieren wir eine Klasse TSampleObject und den zugehörigen Klassentyp TSampleClass sowie zwei Klassenvariablen aSampleClass und aClass. Darüber hinaus haben wir auch einen Konstruktor, einen Destruktor, eine Klassenmethode GetSampleObjectCount und eine Objektmethode GetObjectIndex für die Klasse TSampleObject definiert.
Lassen Sie uns zunächst die Bedeutung der Klassenvariablen aSampleClass und aClass verstehen.
Offensichtlich können Sie TSampleObject und TObject als konstante Werte behandeln und sie aClass-Variablen zuweisen, genau wie Sie der Ganzzahlvariablen i 123 konstante Werte zuweisen. Daher ist die Beziehung zwischen Klassentypen, Klassen und Klassenvariablen die Beziehung zwischen Typen, Konstanten und Variablen, jedoch auf der Ebene der Klasse und nicht auf der Objektebene. Natürlich ist es nicht zulässig, TObject aSampleClass direkt zuzuweisen, da aSampleClass eine Klassenvariable der von TObject abgeleiteten Klasse TSampleObject ist und TObject nicht alle mit dem TSampleClass-Typ kompatiblen Definitionen enthält. Im Gegenteil ist es legal, TSampleObject einer Class-Variablen zuzuweisen, da TSampleObject eine abgeleitete Klasse von TObject ist und mit dem TClass-Typ kompatibel ist. Dies ähnelt genau der Zuweisungs- und Typübereinstimmungsbeziehung von Objektvariablen.
Schauen wir uns dann an, was Klassenmethoden sind.
Die sogenannte Klassenmethode bezieht sich auf die auf Klassenebene aufgerufene Methode, z. B. die oben definierte GetSampleObjectCount-Methode, bei der es sich um eine mit dem reservierten Wort class deklarierte Methode handelt. Klassenmethoden unterscheiden sich von Objektmethoden, die auf Objektebene aufgerufen werden. Objektmethoden sind uns bereits bekannt, und Klassenmethoden werden immer auf der Ebene des Zugriffs und der Steuerung der gemeinsamen Eigenschaften aller Klassenobjekte und der zentralen Verwaltung von Objekten verwendet. In der Definition von TObject finden wir eine große Anzahl von Klassenmethoden wie ClassName, ClassInfo, NewInstance usw. Unter diesen ist NewInstance auch als virtuell definiert, dh als virtuelle Klassenmethode. Das bedeutet, dass Sie die Implementierungsmethode von NewInstance in einer abgeleiteten Unterklasse umschreiben können, um Objektinstanzen dieser Klasse auf besondere Weise zu erstellen.
Sie können den Bezeichner self auch in Klassenmethoden verwenden, seine Bedeutung unterscheidet sich jedoch von self in Objektmethoden. Das Selbst in der Klassenmethode stellt seine eigene Klasse dar, also den Zeiger auf den VMT, während das Selbst in der Objektmethode das Objekt selbst darstellt, also den Zeiger auf den Objektdatenraum. Obwohl Klassenmethoden nur auf Klassenebene verwendet werden können, können Sie Klassenmethoden dennoch über ein Objekt aufrufen. Beispielsweise kann die Klassenmethode ClassName des Objekts TObject über die Anweisung aObject.ClassName aufgerufen werden, da die ersten 4 Bytes im Objektdatenraum, auf die der Objektzeiger zeigt, Zeiger auf die Klasse VMT sind. Im Gegensatz dazu können Sie keine Objektmethoden auf Klassenebene aufrufen und Anweisungen wie TObject.Free müssen illegal sein.
Es ist erwähnenswert, dass der Konstruktor eine Klassenmethode und der Destruktor eine Objektmethode ist!
Was? Konstruktoren sind Klassenmethoden und Destruktoren sind Objektmethoden! Gab es einen Fehler?
Sie sehen, wenn Sie ein Objekt erstellen, verwenden Sie eindeutig eine Anweisung ähnlich der folgenden:
aObject := TObject.Create;
Es ruft eindeutig die Create-Methode der Klasse TObject auf. Verwenden Sie beim Löschen eines Objekts die folgende Anweisung:
aObject.Destroy;
Auch wenn Sie die Free-Methode zum Freigeben des Objekts verwenden, wird die Destroy-Methode des Objekts indirekt aufgerufen.
Der Grund ist sehr einfach: Bevor das Objekt erstellt wird, existiert es noch nicht, sondern nur die Klasse. Sie können nur Klassenmethoden zum Erstellen von Objekten verwenden. Im Gegenteil, das Löschen eines Objekts muss das vorhandene Objekt löschen, nicht die Klasse.
Lassen Sie uns abschließend das Problem der fiktiven Konstrukteure diskutieren.
In der traditionellen C++-Sprache können virtuelle Destruktoren implementiert werden, die Implementierung virtueller Konstruktoren ist jedoch ein schwieriges Problem. Denn in der traditionellen C++-Sprache gibt es keine Klassentypen. Instanzen globaler Objekte sind zur Kompilierungszeit im globalen Datenraum vorhanden, und lokale Objekte von Funktionen sind ebenfalls Instanzen, die zur Kompilierungszeit im Stapelbereich abgebildet sind. Auch dynamisch erstellte Objekte werden mithilfe des neuen Operators in der festen Klassenstruktur platziert Der Heap-Speicherplatz und der Konstruktor sind nur eine Objektmethode, die die generierte Objektinstanz initialisiert. In der traditionellen C++-Sprache gibt es keine echten Klassenmethoden. Auch wenn sogenannte statische klassenbasierte Methoden definiert werden können, werden sie letztendlich als spezielle globale Funktion implementiert, ganz zu schweigen von virtuellen Klassenmethoden, die nur auf bestimmte Objekte abzielen können Instanzen. effizient. Daher geht die traditionelle C++-Sprache davon aus, dass es unmöglich ist, das Objekt selbst basierend auf dem zu generierenden Objekt zu erstellen, bevor eine bestimmte Objektinstanz generiert wird. Es ist in der Tat unmöglich, denn dies würde ein widersprüchliches Paradoxon in der Logik schaffen!
Gerade aufgrund der Schlüsselkonzepte dynamischer Klassentypinformationen, wirklich virtueller Klassenmethoden und klassenbasierter Konstruktoren in DELPHI können virtuelle Konstruktoren implementiert werden. Objekte werden von Klassen produziert. Das Objekt ist wie ein heranwachsendes Baby, und die Klasse ist seine Mutter. Das Baby selbst weiß nicht, was für ein Mensch es in Zukunft werden wird, aber die Mütter nutzen ihre eigenen Erziehungsmethoden, um verschiedene Kinder zu erziehen . Leute, die Prinzipien sind die gleichen.
In der Definition der TComponent-Klasse wird der Konstruktor Create als virtuell definiert, sodass verschiedene Arten von Steuerelementen ihre eigenen Konstruktionsmethoden implementieren können. Das ist die Großartigkeit von Konzepten wie den von TClass erstellten Klassen und auch die Großartigkeit von DELPHI.
................................................. ..
Kapitel 3 Die Sicht von Zeit und Raum in WIN32
Mein alter Vater sah seinen kleinen Enkel an, der mit Spielzeug auf dem Boden spielte, und sagte dann zu mir: „Dieses Kind ist genau wie du, als du klein warst. Es liebt es, Dinge auseinanderzunehmen und hört erst auf, wenn er es zu Ende gesehen hat.“ Wenn ich an meine Kindheit zurückdenke, zerlegte ich oft Spielzeugautos, kleine Wecker, Spieluhren usw. und wurde oft von meiner Mutter beschimpft.
Das erste Mal, dass ich die Grundprinzipien von Computern verstand, hatte mit einer Spieluhr zu tun, die ich auseinandernahm. Es stand in einem Comic, als ich in der High School war. Ein alter Mann mit weißem Bart erklärte die Theorie intelligenter Maschinen, und ein Onkel mit Schnurrbart sprach über Computer und Spieluhren. Sie sagten, dass die zentrale Verarbeitungseinheit eines Computers die Reihe von Notenblättern ist, die für die Aussprache in der Spieluhr verwendet werden, und dass das Computerprogramm die dicht gepackten Höcker auf dem kleinen Zylinder in der Spieluhr sind. Die Drehung des kleinen Zylinders ist äquivalent zur Drehung der Zentraleinheit, während die Höcker, die Musik auf dem kleinen Zylinder darstellen, die Vibration des Notenblatts steuern, um Anweisungen zu erzeugen, die der Ausführung des Programms durch den Zentralprozessor entsprechen. Die Spieluhr gibt eine wunderschöne Melodie ab, die entsprechend der vom Handwerker auf dem kleinen Zylinder eingravierten Musikpartitur abgespielt wird. Der Computer führt die komplexe Verarbeitung auf der Grundlage des vom Programmierer vorprogrammierten Programms durch. Als ich aufs College ging, erfuhr ich, dass der alte Mann mit dem weißen Bart der Wissenschaftsriese Turing war. Seine Theorie der endlichen Automaten förderte die Entwicklung der gesamten Informationsrevolution, und der Onkel mit dem Schnurrbart war der Vater der Computer, von Neumann . Die Computerarchitektur ist immer noch die Hauptarchitekturstruktur von Computern. Die Spieluhr wurde nicht umsonst abgebaut, Mutter kann beruhigt sein.
Nur mit einem einfachen und tiefgreifenden Verständnis können wir tiefgreifende und prägnante Kreationen schaffen.
In diesem Kapitel werden wir die grundlegenden Konzepte im Zusammenhang mit unserer Programmierung im 32-Bit-Windows-Betriebssystem besprechen und die richtige Sicht auf Zeit und Raum in WIN32 festlegen. Ich hoffe, dass wir nach der Lektüre dieses Kapitels ein tieferes Verständnis von Programmen, Prozessen und Threads erlangen, die Prinzipien ausführbarer Dateien, dynamischer Linkbibliotheken und Laufzeitpaketen verstehen und die Wahrheit über globale Daten, lokale Daten und Parameter im Speicher klar erkennen können .
Abschnitt 1 Den Prozess verstehen
Aus historischen Gründen entstand Windows aus DOS. Im DOS-Zeitalter hatten wir immer nur das Konzept eines Programms, nicht jedoch das Konzept eines Prozesses. Zu dieser Zeit verfügten nur normale Betriebssysteme wie UNIX und VMS über das Konzept von Prozessen, und Multiprozesse bedeuteten Minicomputer, Terminals und mehrere Benutzer, was auch Geld bedeutete. Meistens konnte ich nur relativ billige Mikrocomputer und DOS-Systeme verwenden. Mit Prozessen und Minicomputern kam ich erst während meines Studiums der Betriebssysteme in Berührung.
Erst nach Windows 3. Früher konnte unter DOS nur ein Programm gleichzeitig ausgeführt werden, unter Windows konnten jedoch mehrere Programme gleichzeitig ausgeführt werden. Das ist Multitasking. Während ein Programm unter DOS ausgeführt wird, kann dasselbe Programm nicht gleichzeitig ausgeführt werden. Unter Windows können jedoch mehr als zwei Kopien desselben Programms gleichzeitig ausgeführt werden, und jede ausgeführte Kopie des Programms ist ein Prozess. Genauer gesagt generiert jede Ausführung eines Programms eine Aufgabe, und jede Aufgabe ist ein Prozess.
Wenn Programme und Prozesse zusammen verstanden werden, bezieht sich das Wort Programm auf statische Dinge. Ein typisches Programm ist statischer Code und Daten, die aus einer EXE-Datei oder einer EXE-Datei plus mehreren DLL-Dateien bestehen. Ein Prozess ist die Ausführung eines Programms, bei dem es sich um Code und sich dynamisch ändernde Daten handelt, die dynamisch im Speicher ausgeführt werden. Wenn ein statisches Programm ausgeführt werden muss, stellt das Betriebssystem einen bestimmten Speicherplatz für diesen Vorgang bereit, überträgt den statischen Programmcode und die Daten in diese Speicherbereiche und positioniert den Programmcode und die Daten in diesem Bereich neu und ordnet sie zu ausgeführt und so einen dynamischen Prozess erzeugt.
Zwei gleichzeitig ausgeführte Kopien desselben Programms bedeuten, dass sich im Systemspeicher zwei Prozessbereiche befinden, deren Programmfunktionen jedoch gleich sind, sich jedoch in unterschiedlichen, sich dynamisch ändernden Zuständen befinden.
In Bezug auf die Laufzeit des Prozesses wird jeder Prozess gleichzeitig ausgeführt. Der Fachbegriff wird als parallele Ausführung oder gleichzeitige Ausführung bezeichnet. Dies ist jedoch hauptsächlich das oberflächliche Gefühl, das uns das Betriebssystem vermittelt. Tatsächlich wird jeder Prozess zeitgesteuert ausgeführt, das heißt, jeder Prozess belegt abwechselnd die CPU-Zeit, um die Programmanweisungen des Prozesses auszuführen. Bei einer CPU werden nur die Anweisungen eines Prozesses gleichzeitig ausgeführt. Das Betriebssystem ist der Manipulator hinter dem Betrieb des geplanten Prozesses. Es speichert und wechselt ständig den aktuellen Status jedes in der CPU ausgeführten Prozesses, sodass jeder geplante Prozess davon ausgeht, dass er vollständig und kontinuierlich ausgeführt wird. Da die Time-Sharing-Planung von Prozessen sehr schnell erfolgt, entsteht der Eindruck, dass die Prozesse alle gleichzeitig laufen. Tatsächlich ist ein echter gleichzeitiger Betrieb nur in einer Hardwareumgebung mit mehreren CPUs möglich. Wenn wir später über Threads sprechen, werden wir feststellen, dass Threads den Prozess wirklich vorantreiben und, was noch wichtiger ist, dass sie Prozessraum bereitstellen.
In Bezug auf den vom Prozess belegten Raum ist jeder Prozessraum relativ unabhängig und jeder Prozess wird in seinem eigenen unabhängigen Raum ausgeführt. Ein Programm umfasst sowohl Coderaum als auch Datenraum. Sowohl Code als auch Daten belegen Prozessraum. Windows weist tatsächlichen Speicher für den von jedem Prozess benötigten Datenraum zu und verwendet im Allgemeinen Freigabemethoden für Coderaum, um einen Code eines Programms mehreren Prozessen des Programms zuzuordnen. Das heißt, wenn ein Programm über 100 KB Code verfügt und 100 KB Datenraum benötigt, was bedeutet, dass insgesamt 200 KB Prozessraum erforderlich sind, weist das Betriebssystem beim ersten Ausführen des Programms 200 KB Prozessraum und 200 KB Prozessraum zu Der Speicherplatz wird beim zweiten Ausführen des Programms zugewiesen. Wenn ein Prozess gestartet wird, weist das Betriebssystem nur 100 KB Datenspeicherplatz zu, während der Codespeicherplatz den Speicherplatz des vorherigen Prozesses teilt.
Das Obige ist die grundlegende Zeit- und Raumansicht des Prozesses im Windows-Betriebssystem. Tatsächlich gibt es einen großen Unterschied in der Zeit- und Raumansicht des Prozesses zwischen dem 16-Bit- und dem 32-Bit-Betriebssystem.
In Bezug auf die Zeit ist die Prozessverwaltung von 16-Bit-Windows-Betriebssystemen wie Windows 3.x sehr einfach. Es handelt sich eigentlich nur um ein Multitasking-Management-Betriebssystem. Darüber hinaus ist die Aufgabenplanung des Betriebssystems passiv. Wenn eine Aufgabe die Verarbeitung der Nachricht nicht aufgibt, muss das Betriebssystem warten. Aufgrund der Mängel in der Prozessverwaltung des 16-Bit-Windows-Systems belegt ein laufender Prozess die CPU-Ressourcen vollständig. Damit 16-Bit-Windows die Möglichkeit hatte, andere Aufgaben zu planen, lobte Microsoft damals die Entwickler von Windows-Anwendungen dafür, dass sie aufgeschlossene Programmierer seien, so dass sie bereit seien, noch ein paar Codezeilen zu schreiben, um sie zu verschenken Betriebssystem. Im Gegenteil, WIN32-Betriebssysteme wie Windows 95 und NT verfügen über echte Multiprozess- und Multitasking-Betriebssystemfunktionen. Der Prozess in WIN32 wird vollständig vom Betriebssystem geplant. Sobald die Zeitspanne des laufenden Prozesses endet, wechselt das Betriebssystem aktiv zum nächsten Prozess, unabhängig davon, ob der Prozess noch Daten verarbeitet. Streng genommen kann das 16-Bit-Windows-Betriebssystem nicht als vollständiges Betriebssystem angesehen werden, aber das 32-Bit-WIN32-Betriebssystem ist das wahre Betriebssystem. Natürlich wird Microsoft nicht sagen, dass WIN32 die Mängel von 16-Bit-Windows ausgleicht, sondern behauptet, dass WIN32 eine fortschrittliche Technologie namens „Preemptive Multitasking“ implementiert, bei der es sich um eine kommerzielle Methode handelt.
Aus räumlicher Sicht ist der Prozessraum im 16-Bit-Windows-Betriebssystem zwar relativ unabhängig, Prozesse können jedoch problemlos auf den Datenraum des anderen zugreifen. Da es sich bei diesen Prozessen tatsächlich um unterschiedliche Datensegmente im selben physischen Raum handelt, können falsche Adressoperationen leicht zu fehlerhaften Lese- und Schreibvorgängen im Raum führen und das Betriebssystem zum Absturz bringen. Im Betriebssystem WIN32 ist jedoch jeder Prozessraum völlig unabhängig. WIN32 stellt jedem Prozess einen virtuellen und kontinuierlichen Adressraum von bis zu 4G zur Verfügung. Der sogenannte kontinuierliche Adressraum bedeutet, dass jeder Prozess einen Adressraum von $00000000 bis $FFFFFFFF hat und nicht den segmentierten Raum von 16-Bit-Windows. In WIN32 müssen Sie sich keine Sorgen machen, dass Ihre Lese- und Schreibvorgänge unbeabsichtigt die Daten in anderen Prozessbereichen beeinträchtigen, und Sie müssen sich keine Sorgen machen, dass andere Prozesse Ihre Arbeit beeinträchtigen. Gleichzeitig ist der von WIN32 für Ihren Prozess bereitgestellte kontinuierliche virtuelle 4G-Speicher der physische Speicher, der Ihnen vom Betriebssystem mit Unterstützung der Hardware zugeordnet wird. Obwohl Sie über einen so großen virtuellen Speicherplatz verfügen, wird das System niemals ein Byte verschwenden . physisches Gedächtnis.
Abschnitt 2 Prozessraum
Wenn wir DELPHI zum Schreiben von WIN32-Anwendungen verwenden, kümmern wir uns kaum um die interne Welt des Prozesses, wenn er ausgeführt wird. Da WIN32 4G kontinuierlichen virtuellen Prozessraum für unseren Prozess bereitstellt, nutzt die vielleicht größte Anwendung der Welt derzeit nur einen Teil davon. Es scheint, dass der Prozessraum unbegrenzt ist, aber der 4G-Prozessraum ist virtuell, und der tatsächliche Speicher Ihrer Maschine ist möglicherweise weit davon entfernt. Obwohl der Prozess über einen so großen Speicherplatz verfügt, können einige komplexe Algorithmusprogramme aufgrund eines Stapelüberlaufs immer noch nicht ausgeführt werden, insbesondere Programme, die eine große Anzahl rekursiver Algorithmen enthalten.
Daher hilft uns ein umfassendes Verständnis der Struktur des 4G-Prozessraums, seiner Beziehung zum physischen Speicher usw., die Raum-Zeit-Welt von WIN32 klarer zu verstehen, sodass wir in der tatsächlichen Entwicklungsarbeit die richtigen Methoden anwenden können . Weltanschauung und Methodik zur Lösung verschiedener schwieriger Probleme.
Als Nächstes verwenden wir ein einfaches Experiment, um die interne Welt des Prozessraums von WIN32 zu verstehen. Dies erfordert möglicherweise einige Kenntnisse der CUP-Register und der Assemblersprache, ich habe jedoch versucht, es in einfacher Sprache zu erklären.
Wenn DELPHI gestartet wird, wird automatisch ein Project1-Projekt generiert und wir beginnen damit. Legen Sie an einer beliebigen Stelle im Originalprogramm von Project1.dpr einen Haltepunkt fest, beispielsweise am Anfangssatz. Führen Sie dann das Programm aus und es stoppt automatisch, wenn es den Haltepunkt erreicht. Zu diesem Zeitpunkt können wir das CPU-Fenster im Debugging-Tool öffnen, um die interne Struktur des Prozessraums zu beobachten.
Das aktuelle Befehlszeigerregister Eip wird bei $0043E4B8 gestoppt. Da die höchsten beiden Hexadezimalstellen der Adresse, an der sich der Programmbefehl befindet, beide Nullen sind, ist ersichtlich, dass sich das aktuelle Programm an der Adressposition am unteren Rand des 4G befindet Prozessraum, der $00000000 bis ziemlich wenig Adressraum für $FFFFFFFF belegt.
Im Befehlsfeld im CPU-Fenster können Sie den Inhalt des Prozessraums einsehen. Wenn Sie den Inhalt eines Bereichs unter 00400000 US-Dollar anzeigen, werden im Inhalt unter 00400000 US-Dollar eine Reihe von Fragezeichen „???“ angezeigt. Dies liegt daran, dass der Adressraum nicht dem tatsächlichen physischen Bereich zugeordnet wurde. Wenn Sie sich zu diesem Zeitpunkt den Hexadezimalwert der globalen Variablen HInstance ansehen, werden Sie feststellen, dass dieser ebenfalls $00400000 ist. Obwohl HInstance das Handle der Prozessinstanz widerspiegelt, ist es tatsächlich der Startadressenwert, wenn das Programm in den Speicher geladen wird, auch unter 16-Bit-Windows. Daher können wir davon ausgehen, dass das Programm des Prozesses ab 00400000 $ geladen wird, dh der Speicherplatz ab 4 MB im virtuellen 4G-Raum ist der Speicherplatz, in dem das Programm geladen wird.
Ab 00400000 $ und vor 0044D000 $ handelt es sich hauptsächlich um den Adressraum für Programmcode und globale Daten. Im Stapelfeld im CPU-Fenster können Sie die Adresse des aktuellen Stapels anzeigen. Ebenso werden Sie feststellen, dass der aktuelle Stack-Adressraum zwischen $0067B000 und $00680000 liegt und eine Länge von $5000 hat. Tatsächlich beträgt die minimale Stapelspeichergröße des Prozesses 5.000 US-Dollar. Sie ergibt sich aus dem Wert „Min. Stapelgröße“, der beim Kompilieren des DELPHI-Programms auf der Seite „Linker“ von ProjectOptions festgelegt wurde, plus 1.000 US-Dollar. Der Stapel wächst von der oberen Adresse zur unteren Adresse. Wenn der Stapel beim Ausführen des Programms nicht ausreicht, vergrößert das System automatisch den Stapelspeicherplatz zur unteren Adresse Prozessraum. Beim Kompilieren eines DELPHI-Programms können Sie den maximalen Stapelspeicherplatz steuern, der erhöht werden kann, indem Sie den Wert „Maximale Stapelgröße“ auf der Seite „Linker“ in den Projektoptionen festlegen. Insbesondere in Programmen, die tiefe Unterprogrammaufrufbeziehungen enthalten oder rekursive Algorithmen verwenden, muss der Wert für „Maximale Stapelgröße“ angemessen festgelegt werden. Da der Aufruf einer Unterroutine Stapelspeicherplatz erfordert und der Stapel erschöpft ist, gibt das System den Fehler „Stapelüberlauf“ aus.
Es scheint, dass der Prozessraum nach dem Stapelraum freier Speicherplatz sein sollte. Tatsächlich ist dies nicht der Fall. Die relevanten Informationen von WIN32 besagen, dass der 2G-Speicherplatz nach 80.000.000 US-Dollar der vom System genutzte Speicherplatz ist. Es scheint, dass der Prozess wirklich nur 2G-Speicherplatz besitzen kann. Tatsächlich beträgt der Speicherplatz, den ein Prozess wirklich besitzen kann, nicht einmal 2G, da der 4M-Speicherplatz von 00000000 $ bis 00400000 $ ebenfalls ein eingeschränkter Bereich ist.
Aber egal was passiert, die Adressen, die unser Prozess verwenden kann, sind immer noch sehr breit gefächert. Vor allem nach dem Stapelplatz und zwischen 80.000.000 US-Dollar ist es das Hauptschlachtfeld im Prozessraum. Der vom Prozess vom System zugewiesene Speicherplatz wird diesem Bereich zugeordnet, die vom Prozess geladene dynamische Linkbibliothek wird diesem Bereich zugeordnet, und der Thread-Stapelbereich des neuen Threads wird ebenfalls diesem Bereich zugeordnet, fast alle Vorgänge mit Speicherzuweisung Alle werden diesem Speicherplatz zugeordnet. Bitte beachten Sie, dass die hier erwähnte Zuordnung bedeutet, dass der Prozessraum, der nicht dem tatsächlichen Speicher zugeordnet ist, nicht verwendet werden kann, ebenso wie die Zeichenfolge „“ im Befehlsfeld des CPU-Fensters während des Debuggens. ???".
............
Danke fürs Lesen!