Lade...
 

Address Space

Address Space

Hinweis
Die hier aufgeführten Informationen beziehen sich auf Umgebungen mit 32Bit Datenbanken:
Mit 64Bit Datenbanken sollten bei einer minimalen OS_AS_SIZE von 0x5000000000 keine Address Space Meldungen mehr auftreten.

Jeder Prozess hat in Windows seinen eigenen Adressraum. Das theoretische Maximum liegt bei 4 GByte, bedingt durch die 32-Bit-Architektur (unter Windows 32 Bit). Windows zweigt für sich 2 GByte ab. Die verbleibenden 2 GByte stehen ClassiX® jedoch nicht uneingeschränkt zur Verfügung, denn die Programmbibliotheken (DLLs), die ClassiX® benutzt, werden ebenfalls in diesen 2 GByte-Adressraum eingeblendet.

An dieser Stelle sei auf den Unterschied zwischen Adressraum und Arbeitsspeicher hingewiesen: Auch wenn jedem Prozess 2 GByte Adressraum zur Verfügung stehen, heißt das nicht, dass tatsächlich auch 2 GByte Arbeitsspeicher für diesen Prozess reserviert werden. Windows blendet erst dann Arbeitsspeicher in den jeweiligen Adressraum ein, wenn er gebraucht wird. Im Fall von DLLs wird Arbeitsspeicher sogar in mehrere Prozesse gleichzeitig eingeblendet: So kann jeder Prozess eine DLL benutzen, ohne dass jedes Mal Arbeitsspeicher verbraucht wird.

Beim Adressraum handelt es sich somit um virtuelle Adressen, die unabhängig vom physikalisch vorhandenen Hauptspeicher durch das Betriebssystem verwaltet werden. Für 32-Bit-Adressen ergibt das einen Bereich von 0 bis 0xFFFFFFFF, der auf den Windows-Platformen wie folgt aufgeteilt wird:

Range Usage
0K - ~64K (0xFFFF) Not writable. This boundary is approximate due to the way the system loads some features of Microsoft® MS-DOS®. This memory is private to the process.
~64K (0x10000) -
4 MB (0x3FFFFF)
Reserved for MS-DOS compatibility. This memory is fully readable and writable by the process. However, this range of memory may have some MS-DOS–related structures or code in it, so processes should not arbitrarily read from or write to it. This memory is private to the process.
4MB (0x400000) -
2GB (0x7FFFFFFF)
Available for code and user data. User data is readable and writable by the process. Code is execute-only. This memory is private to the process.
2GB (0x80000000) -
3GB (0xBFFFFFFF)
Shared area, readable and writable by all processes. A number of system DLLs and other data are loaded into this space.
3GB (0xC0000000) -
4GB (0xFFFFFFFF)
System memory, readable or writable by any process. However, this is where low-level system code resides, so writing to this region may corrupt the system, with potentially catastrophic consequences.

ObjectStore stellt nun eine Besonderheit dar: Es reserviert ein durchgehendes Stück Adressraum, den es benutzt, um Teile der Datenbank in den Adressraum des Prozesses einzublenden. Aus Performancegründen sollte dieses Fenster so groß wie möglich sein, durch die Einschränkungen, die weiter oben erläutert wurden, ist dieses Fenster in der Praxis jedoch immer auf einen Adressraum begrenzt, der deutlich kleiner ist als 2 GByte.

Adressraum Belegt durch
0x00000000-0x00400000 Reserviert aus Kompatibilitätsgründen
0x00400000-0x10000000 Programmcode
0x10000000-0x70000000 Programmbibliotheken
0x70000000-0x80000000 Systembibliotheken
0x80000000-0xFFFFFFFFF Reserviert für Windows

Die Tabelle zeigt, dass ClassiX® und ObjectStore sich den Adressbereich von 0x400000 bis 0x7FFFFFFF teilen müssen.

Jeder Prozess bekommt den gleichen virtuellen Adressraum zugeteilt; wenn ClassiX® mehrfach gestartet wird, wirkt sich dies nicht nachteilig auf die Zuordnung der PSR entsprechend dem OS_AS_SIZE-Wert aus.

Natürlich werden die virtuellen Adressen der PSR von Zeit zu Zeit realen Speicheradressen zugeordnet. Der Größe des dafür reservierte Bereichs wird mit OS_CACHE_SIZE vorgegeben. Diese Größe ist - im Gegensatz zur PSR - durchaus vom real vorhandenen Speicher abhängig und reduziert sich, wenn ClassiX® auf der gleichen Maschine mehrfach gestartet wird.

Wenn nicht anders konfiguriert, belegt ObjectStore den Adressraum zwischen 0x30000000 und 0x50000000 (das sind 0x20000000 Bytes oder 512 MBytes). Dieser Adress-Bereich wird PSR (Persistent Storage Region) genannt. Über die Umgebungsvariable OS_AS_START kann die Startadresse, über die Variable OS_AS_SIZE die Größe der PSR verändert werden. ObjectStore versucht dann, einen durchgehenden Adressbereich zu reservieren.

Auf einer typischen 32Bit ClassiX-Installation kann OS_AS_SIZE auf bis zu 0x44000000 gesetzt werden. Das entspricht ca. 1,1 GBytes, die PSR liegt dann i.d.R. zwischen 0x126e0000 und 0x566e0000. In den Adressraum darüber und darunter werden DLLs geladen (siehe auch Angabe DLLs in classix.ini).

Auf manchen Computern ist es nicht möglich, einen so großen Adressbereich für die PSR zu reservieren. In diesem Fall wurde eine DLL irgendwo in diesen Adressbereich geladen, so dass ObjectStore kein ausreichend großes durchgehendes Stück Adressraum reservieren kann. Meist sind das DLLs von Treibern, in seltenen Fällen DLLs des Betriebssystems. ClassiX® bietet zwei Möglichkeiten, solche DLLs zu finden:

  • Logbuch: ClassiX® protokolliert beim Start, welche DLL wohin geladen wurde. Hier ist anschließend jeder Adressbereich zu kontrollieren, ob er irgendwo im Bereich zwischen 0x13000000 und 0x50000000 liegt und dadurch einen PSR verhindert. Dafür muss das Logging über die logging.ini so konfiguriert werden, dass der Bereich cx.omgr Debug-Informationen schreibt (cx.omgr=DEBUG in die logging.ini eintragen)
    2006-01-18 11:27:17,811 DEBUG cx.omgr - Loaded DLLs:
    2006-01-18 11:27:18,295 DEBUG cx.omgr - VERSION.dll 77bd0000-77bd8000
    2006-01-18 11:27:18,295 DEBUG cx.omgr - dbghelp.dll 59dd0000-59e71000
    2006-01-18 11:27:18,295 DEBUG cx.omgr - rasadhlp.dll 76f80000-76f86000
    2006-01-18 11:27:18,295 DEBUG cx.omgr - WLDAP32.dll 76f20000-76f4d000
    2006-01-18 11:27:18,295 DEBUG cx.omgr - winrnr.dll 46f70000-46f78000
    2006-01-18 11:27:18,295 DEBUG cx.omgr - DNSAPI.dll 76ee0000-76f07000
     
  • Modul "Geladene DLLs":  Zunächst ist die Umgebungsvariable OS_AS_SIZE so niedrig zu setzen, dass ClassiX® startet. Im Modul "Geladene DLLs" werden alle geladenen DLLs samt des belegten Adressbereiches angezeigt. Durch Sortieren nach Adressbereich lässt sich schnell herausfinden, welche DLL einen großen PSR verhindert.

Für solche DLLs kann mit dem Utility rebase.exe eine andere, weniger störende Ladeadresse vergeben werden. Mit rebase -? erhält man eine Übersicht sämtlicher möglicher Parameter. Für unsere Zwecke brauchen wir nur mit rebase x.dll -b nnnnnnnn die DLL x auf die neue Ladeadresse nnnnnnnn zu verschieben (sowohl 0xnnnnnnnn als auch nnnnnnnn werden akzeptiert).

Windows ist im abgesicherten Modus zu starten, damit rebase erfolgreich sein kann. Falls rebase die Ladeadresse nicht ändern kann, meldet es keinen Fehler, sondern tut einfach nichts.

Bekannte problematische DLLs: Einige DLLs sind in bestimmten Umgebungen dafür bekannt, oben beschriebene Fehler zu verursachen. In einigen Fällen ist es möglich das Problem zu lösen ohne ein Rebase durchzuführen:

  • MSCTF.DLL: Eine DLL, die für erweiterte Texteingabe verwendet wird. Das Laden kann auf folgende Weise unterbunden werden: Unter Systemsteuerung->Regions- und Sprachoptionen->Sprachen->Details->Erweitert (auf englischen Systemen in Settings->Control Panel->Text Services->Advanced) lassen sich die erweiterten Textdienste deaktivieren. Natürlich setzt dieses Vorgehen voraus, das die erweiterten Textdienste (Handwriting, Ost-Asiatische Sprachen, ...) nicht verwendet werden.

Hinweis: Wenn beim Start das ClassiX®-Systems die bisher immer tolerierte Größe für OS_AS_SIZE plötzlich zu groß ist, liegt die Ursache oft bei der Installation neuer Software-Komponenten oder Treibern. Dabei wurden systemnahe DLLs mit ungünstigeren Ladeadressen eingeführt, die auch beim Start des ClassiX®-Systems aktiviert werden.
Abhilfe schafft die oben beschriebene Suche nach den störenden DLLs und anschließende Verschiebung der Ladeadresse mit rebase.exe auf einen günstigeren, mehr an den Rändern liegenden Wert.
Oftmals reicht es aber schon, neuere Treiber oder Service-Packs aufzuspielen.
 

Address Space - Überlauf

Wenn ObjectStore eine Page zu einem Client schickt, können auf dieser Page liegende Objekte mit Pointern auf weitere Objekte auf anderen Pages verweisen. Welcher dieser Pointer demnächst vom Programm derefenziert wird, kann ObjectStore nicht wissen, aber es sorgt dafür, dass das referenzierte Objekt dann auch mit maximaler Geschwindigkeit in den Cache des Clients geladen werden kann. Für alle diese Objekte, die durch Dereferenzierung eines Pointers potentiell aus der Datenbank geholt werden könnten, legt ObjectStore bereits Adressen im virtuellen Adressraum des Clients (in der PSR) fest.
Der Nachteil dieses Verfahrens: wenn viele persistente Objekte verarbeitet werden, können die (virtuellen) Adressen der PSR verbraucht sein, es kommt zum Überlauf.

Das ClassiX®-System behandelt Adress Space - Überlauf auf InstantView®-Ebene in folgenden Fällen:

  • Beim Iterieren über persistente Objekte, welche die Elemente einer Collection, eines Vektors oder einer ObjectList sind.
    Das Statement, das den Address Space - Überlauf ausgelöst hat, muss wiederholt werden, nachdem Adress Space explizit freigegeben wurde. Leider können nicht alle Statements wiederholt werden! Address Space - Überlauf bei einem Statement, dass die die Datenbank oder die sonstige Programmumgebung verändert, führt zum Abbruch, da es nicht möglich ist, die Veränderungen sicher zurückzunehmen.
    Iterieration über eine Collection behandelt nur dann Address Space - Überlauf, wenn iterate(UNSAFE) benutzt wird.
     
  • Beim Sortieren der in einem ObjectListView-Windowobjekt dargestellten Objekte. Die Möglichkeiten der Freigabe von Address Space sind größer, wenn Objekte mit FillObox zunächst unsortiert "eingefüllt" werden und die Sortierung anschließend erfolgt:

    statt

    besser

           [] SetSort   // keine Sortierung
           ... FillObox
           "name", "firstName", "dateOfBirth" SetSort Sort   // jetzt sortieren
          
    Die zweite Variante ist auch aus Gründen der Performance vorzuziehen.

Tritt Address-Space-Überlauf beim Erzeugen oder Löschen eines Indexes auf, ist die Multi-Transaktions-Variante von AddIndex bzw. DropIndex zu benutzen. Dabei ist die Anzahl der Objekte anzugeben, die pro Transaktion verarbeitet werden sollen.