x86-Programmierung und -Betriebsarten (Teil 5)

Probleme der Segmentierung

Eine Möglichkeit, den virtuellen Adressraum größer als den tatsächlich vorhandenen physikalischen Speicher zu machen, haben wir bereits beim Protected Mode und den damit verbundenen Segmentdeskriptoren kennen gelernt. In den Segmentdeskriptoren ist ein Bit P (Present) vorhanden, das angibt, ob sich das Segment auch tatsächlich im Speicher befindet. Versucht der Prozessor ein Segment anzusprechen, dessen P-Bit gelöscht ist - das heißt es befindet sich nicht im Speicher - so wird die Exception "Segment nicht vorhanden" ausgelöst. Das Betriebssystem kann das fragliche Segment nun in den Speicher laden und dem Befehl erneut die Chance geben, auf das Segment zuzugreifen. Damit ist es möglich, für ein Programm mehr Segmente zu erzeugen als auf einmal in den Speicher passen. Die ausgelagerten Segmente werden bei Bedarf einfach eingelesen. Ist im Speicher nicht mehr genügend Platz vorhanden, so müssen ein oder mehrere andere Segmente ausgelagert werden, um Raum für das neu eingelesene zu schaffen.

Damit beginnen aber nun schon die Probleme. Die Daten können nur segmentweise ausgelagert und eingelesen werden und zudem stimmt die Größe der Segmente mit der Größe der Datenstrukturen überein, die sie enthalten. Das Datensegment für eine umfangreiche Zeichnung oder das Codesegment für ein leistungsstarkes Programmmodul können sehr groß sein. Demgegenüber ist ein Datensegment, das nur eine Anredefloskel für einen Brief enthält oder ein Codesegment, das eine einfache Prozedur speichert, meist sehr klein. Soll nun ein großes Segment von Festplatte in den Speicher geladen werden, ist möglicherweise eine Vielzahl kleinerer Segmente auszulagern. Besonders ärgerlich wird die ganze Angelegenheit, wenn in dem eingelesenen Segment nur ein einziges Byte oder Wort angesprochen werden muss, aber anschließend sofort ein Zugriff auf den Code oder die Daten in einem der ausgelagerten Segmente erfolgen soll: das Segment also erneut auslagern, das Codesegment einlesen. Benötigt das Programm nochmals Daten vom jetzt erneut ausgelagerten Datensegment, nochmals alles von vorne - und so weiter.

Ein weiteres Problem tritt bei sparsamem Speicherausbau auf: Für das Datenbanksegment bleibt vom physikalischen Hauptspeicher nur der Platz, den Betriebssystem, Treiber, Systemtabellen und wenigstens ein Codesegment des aktuellen Programms übriggelassen haben. Ist das ausgelagerte Segment nun größer als dieser restliche Speicher, so kann es nicht eingelesen werden. Stehen beispielsweise maximal 990 KByte zur Verfügung, besitzt das Datenbanksegment aber eine Größe von 1 MByte, so kann das Segment nicht eingelesen und das Programm damit nicht ausgeführt werden.

Das Betriebssystem muss daher eine ganz ordentliche Menge an Arbeit leisten: ermitteln, welches Segment denn am besten ausgelagert wird, ob der jetzt freie Speicher ausreicht, gegebenenfalls ein weiteres Segment auslagern et cetera. Entsprechend zäh kann der Swap-Vorgang ablaufen, was Sie unter Windows an der unentwegten Beschäftigung der Festplatte vernehmen können. Es gibt aber eine bessere Möglichkeit: Paging.

Da sich alle Segmente im vorhandenen physikalischen Speicher befinden müssen, der kleiner als 4 GByte ist, liegen auch die Basisadressen aller Segmente bisher innerhalb des Adressbereichs des physikalischen Speichers. Bei einem älteren PC-System mit einem Hauptspeicher von beispielsweise nur 4 MByte sind damit alle Basisadressen kleiner als 4 MByte, das heißt der gesamte lineare Adressbereich von 4M bis 4G wird nicht benutzt. Mit anderen Worten - zirka 99,9 Prozent des linearen Adressbereichs sind ungenutzt. Eine Menge Speicher für viele, viele Segmente!