Der
HEAP DEBUGGER V2.0
f?r
BORLAND PASCAL V7.0
(DOS, DOS/DPMI, WINDOWS)
Copyright 1995
by
AIT GmbH
Alte Gasse 12 - 86152 Augsburg
Germany
Tel. +49 (821) 514868
Fax: +49 (821) 514831
FIDO-Net: Karsten Strobel @ 2:2480/300.7
Internet: [[Email Removed]]
INHALT
EINF?HRUNG
Der Sinn des Heap Debuggers ......................................... 3
Was der Heap Debugger kann .......................................... 3
Was der Heap Debugger NICHT kann .................................... 3
Der Umgang mit dynamischem Speicher ................................. 3
Versionen und Zielplattformen ....................................... 4
Liste der Dateien ................................................... 5
Sharewarekonzept .................................................... 5
Lizenzbedingungen ................................................... 5
Nutzungsempfehlungen und Haftungsausschl?sse ........................ 6
ANWENDUNG DES HEAP DEBUGGERS
Den Heap Debugger einbinden ......................................... 6
Compiler- und Linkereinstellungen ................................... 7
Wenn die Initialisierung fehlschl?gt ................................ 7
Der Heap Debugger Report ............................................ 8
Besondere Meldungen im Heap Debugger Report ......................... 9
Interpretation des Reports .......................................... 10
Auffinden von Bugs .................................................. 11
Arbeiten mit einem externen Debugger ................................ 11
Compilerschalter in USEHDEB ......................................... 12
HEAP DEBUGGING IM DETAIL
Overlays ............................................................ 13
DLLs ................................................................ 13
Programminstanzen (Windows) ......................................... 14
Interrupts .......................................................... 14
Stabilit?t und Performance .......................................... 14
Eingriffsm?glichkeiten f?r den Programmierer ........................ 15
BEKANNTE EINSCHR?NKUNGEN UND PROBLEME
Mark/Release ........................................................ 16
MemAllocSeg ......................................................... 17
BGI ................................................................. 18
TMemoryStream ....................................................... 18
Heap?berlauf ........................................................ 18
Programmabbruch ..................................................... 19
WINCRT .............................................................. 19
Seite 3
EINF?HRUNG _____________________________________________________________
___ Der Sinn des Heap Debuggers ________________________________________
Der Heap Debugger ?berwacht (fast) alle vom Programm vorgenommenen Heap-
Operationen und f?hrt unter anderem eine Liste ?ber alle nicht freigege-
benen Heapspeicherbereiche. Der Programmierer, der den Heap Debugger
w?hrend der Entwicklungsphase in sein Programm einbindet, wird nach je-
dem Programmabschlu? auf ?briggebliebene Speicherbl?cke hingewiesen.
Der Heap Debugger macht das Auffinden der Fehlerquellen extrem einfach,
weil er (meistens) einen Hinweis auf die Sourcecodestelle (Dateiname und
Zeile) liefert, an der die inkorrekte Heap-Operation vorgenommen wurde
bzw. an der ein sp?ter nicht wieder freigegebener Speicherblock allo-
ziert wurde.
Hierzu bedient sich der Heap Debugger der Debug-Informationen f?r den
externen Debugger, die (optional) an das vom Compiler erzeugte EXE-File
angeh?ngt werden.
___ Was der Heap Debugger kann _________________________________________
Der Heap Debugger ?berwacht alle Allokationen von Heapspeicher, die mit
den Befehlen
- GetMem
- New
- FreeMem
- Dispose
vorgenommen werden. Auch Aufrufe dieser Routinen aus der Run-Time-
Library und aus Programmteilen heraus, die nicht im Sourcecode vorliegen
(z.B. fremde TPUs), werden ber?cksichtigt.
Alle nicht korrekt deallokierten Heapspeicherbl?cke und sonstige fehler-
hafte Heap-Operationen werden im Heap Debugger Report ausgegeben.
___ Was der Heap Debugger NICHT kann ___________________________________
Folgende Heap-Operationen k?nnen vom Heap Debugger NICHT mitverfolgt
werden:
- Mark und Release (d?rfen gar nicht verwendet werden !)
- direkte Operationen mit dem globalen Heap (DPMI+Windows),
also alle "Global..."-Aufrufe
- direkte Operationen mit dem lokalen Heap (Windows),
also alle "Local..."-Aufrufe
___ Der Umgang mit dynamischem Speicher ________________________________
In Programme, die intensiv mit Heapspeicher umgehen, schleichen sich
nicht selten heimt?ckische Programmierfehler ein: Wenn n?mlich dynamisch
angeforderte Speicherbereiche nicht korrekt wieder freigegeben werden,
schrumpft der noch verf?gbare Heapspeicher nach und nach so weit zu-
Seite 4
sammen, da? irgendwann f?r eine neue Anforderung nicht mehr gen?gend
Platz zur Verf?gung steht und das Programm abbricht oder -st?rzt.
Zum v?lligen Aufzehren des Heapspeichers kommt es nat?rlich nur, wenn
Allokationen ohne entsprechende Deallokationen nicht nur einmal, sondern
wiederholt durchgef?hrt werden. Wenn dieses z.B. mit der Anwahl einer
bestimmten Programmfunktion durch den Benutzer verbunden ist, dann kann
dies vielleicht einige hundert Male gut gehen, bis der ?brige Heapspei-
cher aufgebraucht ist. So intensiv werden aber Programme nur selten vom
Programmierer getestet. Also kommen so bedingte Abst?rze in der Regel
erst beim Benutzer vor, der daf?r nat?rlich keine Erkl?rung hat.
Es gibt auch Allokationen, die nur einmalig, also zum Beispiel in der
Initialisierungsphase vorgenommen werden, weil das Programm Speicher-
platz f?r quasi-statische Variablen ben?tigt. Solche Variablen (bzw.
Strukturen oder Objekte) k?nnte der Pogrammierer auch im Datensegment
(als globale Variablen) allokierten, aber da die Gr??e des Datensegmen-
tes auf insgesamt 64KB beschr?nkt ist, wird manchmal der Heap als Aus-
weg gew?hlt. Wenn solche (nur einmalig allokierten) quasi-statischen
Variablen nicht wieder freigegeben werden, so ist dies nur ein Sch?n-
heitsfehler, hat aber sonst keine Konsequenzen. Der Heap Debugger be-
m?ngelt aber nat?rlich auch solche Delikte.
Besonders t?ckisch sind Deallokationsfehler, d.h. fehlerhafte Freigaben
von Heapspeicher. Ein Deallokationsfehler liegt vor, wenn bei der
Freigabe von Heapspeicher eine falsche Adresse oder eine falsche L?nge
angegeben wird, also zu der unternommenen Deallokation zuvor keine pas-
sende Allokation erfolgt ist. Da sich die Runtime-Library weitgehend auf
die Angaben des Programmierers verl??t, k?nnen Deallokationsfehler ver-
heerende Folgen haben.
Besonders die Objektorientierte Programmierung macht intensiv von Heap-
speicher Gebrauch. Zu jeder neuen Instanz eines Objektes wird ein Heap-
speicherblock f?r die Felder des Objektes angefordert, der beim L?schen
der Instanz wieder freigegeben werden mu?. Hierzu bedient man sich der
Befehle New und Dispose in der speziell f?r OOP-Zwecke erweiterten
Syntax. Auch "vergessene" Objekte konsumieren Heapspeicher.
___ Versionen und Zielplattformen ______________________________________
Der Heap Debugger wurde entwickelt und getestet mit
Borland Pascal V7.0 und V7.01
mit den Zielsystemen
- Real Mode (hierf?r HDEB7?.TPU)
- Protected Mode (hierf?r HDEB7?.TPP)
- Windows (hierf?r HDEB7?.TPW)
unter
- DOS 6.2x
- Windows V3.1
- Windows for Workgroups V3.11
- Windows NT 3.5 Workstation
- OS/2 V2.11
Eine Version f?r Delphi V1.0 f?r Windows ist in Vorbereitung.
Seite 5
___ Liste der Dateien __________________________________________________
USEHDEB.PAS .... Unit zum Einbinden in Pascalprogramme, f?r
DOS, DOS/DPMI und WINDOWS
HDEB7S.TPU ..... Der Kern des Heap Debuggers, nur bei
Sharewareversionen, f?r DOS/Real Mode
HDEB7S.TPP ..... Der Kern des Heap Debuggers, nur bei
Sharewareversionen, f?r DOS/Protected Mode
HDEB7S.TPW ..... Der Kern des Heap Debuggers, nur bei
Sharewareversionen, f?r Windows
HDEB7F.TPU ..... Der Kern des Heap Debuggers, nur bei
Vollversionen f?r DOS/Real Mode
HDEB7F.TPP ..... Der Kern des Heap Debuggers, nur bei
Vollversionen f?r DOS/Protected Mode
HDEB7F.TPW ..... Der Kern des Heap Debuggers, nur bei
Vollversionen f?r Windows
VIEWME.EXE ..... Der Heap Debugger in Bildern (VGA)
README.TXT ..... Dieser Text (englisch)
LIESMICH.TXT ... Dieser Text (deutsch)
DIZFILES.ZIP ... F?r Sysops, nur in Sharewareversionen
SHARWARE.ZIP ... Diese Datei ist nur in Vollversionen
enthalten und enth?lt die Sharewareversion
BESTELL.TXT .... Bestellformular (deutsch)
ORDER.TXT ...... Bestellformular (englisch)
___ Sharewarekonzept ___________________________________________________
Der Heap Debugger ist Shareware, also KEINE Public Domain oder Freeware!
Die ?ber Sharewarevertriebswege verbeitete Version des Heap Debuggers in
den Dateien HDEB7S.* ("S"=Shareware) und die Begleitdateien und die
Datei USEHDEB.PAS d?rfen zu Testzwecken genutzt und an andere weiterge-
geben werden.
Die Sharewareversion ist gegen?ber der Vollversion im Leistungsumfang
beschr?nkt: Die Sharewareversion des Heap Debuggers verfolgt nur die
ersten 50 Allokationen von Heapspeicherbl?cken. Alle folgenden Allo-
kationen werden ignoriert. Bei ?berschreitung des Sharewarelimits wird
bei Ausgabe des Reports (bei Programmende) eine entsprechende Meldung
ausgegeben.
Registrierte Vollversionen des Heap Debuggers beinhalten die Dateien
HDEB7F.* ("F"=Full). Diese Dateien d?rfen NICHT an Dritte weitergegeben
oder ihnen zug?nglich gemacht werden.
___ Lizenzbedingungen __________________________________________________
Wer den Heap Debugger in der unbeschr?nkten Vollversion nutzen m?chte,
mu? eine Registrierung bei den Autoren vornehmen und erh?lt im Zuge der
Lieferung der Vollversion eine Lizenz zur Nutzung der Vollversion auf
einem einzelnen Arbeitsplatz.
Bei Nutzung des Heap Debuggers auf mehreren Arbeitspl?tzen m?ssen auch
mehrere Registrierungen bestellt werden. Hierf?r bieten wir Staffel-
preise an.
Seite 6
Ein Registrierungsformular ist in der Datei BESTELL.TXT vorbereitet.
Es ist ausdr?cklich untersagt, die Vollversion des Heap Debuggers
weiterzugeben. Dies betrifft insbesondere die Dateien HDEB7F.*
___ Nutzungsempfehlungen und Haftungsausschl?sse _______________________
Obwohl wir den Heap Debugger vor der Ver?ffentlichung ausf?hrlich getes-
tet haben, k?nnen wir keine Garantie f?r einwandfreie Funktion oder Feh-
lerfreiheit dieser Software ?bernehmen.
Wir empfehlen die Nutzung des Heap Debuggers w?hrend der Entwicklungs-
phase. Nach Fertigstellung eines Softwareprodukts sollte unserer Meinung
nach der Heap Debugger nicht mehr eingebunden werden.
Der Heap Debugger soll Ihnen bei der Softwareentwicklung helfen, Fehler
bei der Speicherverwaltung zu vermeiden oder zu beseitigen. Wir weisen
aber auch auf die zus?tzlichen Gefahren f?r die Stabilit?t einer Soft-
ware, die den Heap Debugger einbindet, hin. N?heres hierzu siehe Ab-
schnitt "Stabilit?t und Performance".
Bei Lieferungen dieser Software erstreckt sich unsere Garantie aus-
schlie?lich auf die Lesbarkeit des gelieferten Datentr?gers. Wir ?ber-
nehmen keinerlei Haftung f?r Sch?den, die durch Benutzung des Heap
Debuggers eventuell entstehen werden.
ANWENDUNG DES HEAP DEBUGGERS ___________________________________________
___ Den Heap Debugger einbinden ________________________________________
Um den Heap Debugger in ein eigenes Programm einzubinden, m?ssen Sie nur
die Unit UseHDeb in die Uses-Klausel Ihres Hauptprogramms aufnehmen.
Beispiel:
PROGRAM MyProg;
UseHDeb,
\ /
\/
USES Drivers, Objects, Views, Menus, ...
Es ist sinnvoll, die Unit UseHDeb als erste Unit in der Uses-Klausel
aufzuf?hren. Die Initialisierung des Heap Debuggers erfolgt ?ber den
Initialisierungsteil dieser Unit. Erst nach der Initialisierung kann der
Heap Debugger Heap-Operationen "beobachten". Deshalb sollte die Initia-
lisierung von UseHDeb m?glichst vor der Initialisierung anderer Units,
die eventuell schon Heap-Operationen machen, vorgenommen werden.
Keine der Units, von denen die Units UseHDeb und HDeb7? ihrerseits di-
rekt oder indirekt Gebrauch machen, nimmt in der Initialisierungsphase
Heap-Allokationen vor. Der Heap Debugger erh?lt also von allen Heap-
Operationen Kenntnis, sofern keine der vom Heap Debugger genutzten Units
modifiziert worden sind.
Seite 7
___ Compiler- und Linkereinstellungen __________________________________
"D+":
Der Heap Debugger wird nur initialisiert, wenn die Unit UseHDeb mit der
Compileroption "D+" (Debug-Informationen ein) ?bersetzt wird. Das liegt
daran, da? fast die gesamte Unit UseHDeb mit Hilfe der Klausel
{$IFOPT D+}...{$ENDIF} von der Compilierung ausgeschlossen ist, wenn die
Option D+ nicht eingeschaltet ist. Dieser Schalter kann also zum Ein-
und Ausschalten des Heap Debuggers verwendet werden. Theoretisch k?nnte
der Heap Debugger allerdings auch ohne eingeschaltetes D+ laufen.
F?r alle anderen Units, die in Ihr Programm eingebunden werden, sowie
f?r das Hauptprogramm gilt: Nur wenn mit der Option D+ ?bersetzt wird,
kann der Heap Debugger in seinem Report Referenzen auf diese Quellda-
teien und Zeilennummern angeben.
"Link-Puffer: Festplatte" und "Externer Debugger":
Damit der Heap Debugger im Report Referenzen auf Quelldateien und Zei-
lennummern liefern kann, m?ssen die dazu notwendigen Debug-Informa-
tionen in das vom Compiler erzeugte EXE-File (bzw. DLL) geschrieben wer-
den. Neben der Compileroption D+ werden dazu au?erdem die Einstellungen
"Link-Puffer: Festplatte" und "Externer Debugger" ben?tigt. Unter Win-
dows hei?t die letzte Option "Debug-Info in EXE".
"Unit-Verzeichnis: \BP\RTL\WIN" (DOS/DPMI und Windows):
Die Unit UseHDeb ben?tigt im Protected Mode (DOS+Windows) die Unit
WINPROCS. Diese befindet sich gew?hnlich im Verzeichnis "\BP\RTL\WIN".
Da unter DOS dieses Verzeichnis normalerweise nicht als Unit-Verzeichnis
(siehe Option-->Verzeichnisse) eingestellt ist, m?ssen Sie dieses Ver-
zeichnis selbst in der Liste der Unit-Verzeichnisse erg?nzen.
___ Wenn die Initialisierung fehlschl?gt _______________________________
Die Initialisierung des Heap Debuggers wird von dem Initialisierungteil
der Unit UseHDeb vorgenommen. Bei Fehlschlagen der Initialisierung gibt
UseHDeb die Meldung "Heap Debugger konnte nicht initialisiert werden !"
aus und stoppt das Programm mit dem Kommando HALT.
Das Fehlschlagen der Initialisierung kann folgende Ursachen haben:
- Sie verwenden eine modifizierte Run-Time-Library, die in
einem f?r den Heap Debugger wichtigen Punkt nicht mit dem
Original von Borland ?bereinstimmt.
- Sie verwenden ein von uns nicht getestetes Betriebssystem
oder spezielle, von uns nicht getestete Tools (z.B. zur
Speicherverwaltung).
- Sie verwenden eine von uns nicht getestete Compilerversion.
- Es wurden keine freien Interruptvektoren gefunden. Der
Heap Debugger ben?tigt drei freie Interrupts. In diesem
Falle ist wahrscheinlich unsere Testmethode zum Finden
freier Interrupts verantwortlich. Es kommt selten vor,
da? tats?chlich alle Interrupts belegt sind.
- Der Heap Debugger ist schon initilisiert. Dies sollte bei
Verwendung der Unit UseHDeb nicht vorkommen.
Seite 8
Wenn bei Ihrem System die Initialisierung des Heap Debuggers fehlschla-
gen sollte, dann versuchen Sie bitte zun?chst, Ihr Programm in einer von
uns getesteten Konfiguration (z.B. MSDOS 6.2, ggf. Windows 3.1) ohne
vorheriges Laden irgendwelcher spezieller Speichermanager oder Multi-
tasker zu laden. Beobachten Sie, ob der Heap Debugger in dieser Konfi-
guration initialisiert werden kann.
Bitte informieren Sie uns ?ber Konfigurationen, in denen der Heap
Debugger nicht betrieben werden kann (m?glichst per email).
___ Der Heap Debugger Report ___________________________________________
Der Heap Debugger gibt beim Beenden des untersuchten Programms einen Re-
port aus. Dies geschieht in der Exit-Prozedur der Unit UseHDeb.
Der Heap Debugger Report hat in der Regel folgenden Aufbau (Beispiel):
HEAP DEBUGGER DIAGNOSE:
2 Pointer wurden registiert (*1)
1 Debug-Eintraege vorhanden (*2)
auflisten (J/N) ? j
(*3) (*4) (*5) (*6) (*7) |------(*8)------|
Nr Pointer Size Flags Aufrufer Datei Zeile
2 1A41:0000 256 0000[122D]:0044 HEAPBUG.PAS 16
(*1): Hier wird angegeben, wieviele Heap-Allokationen der Heap Debugger
insgesamt mitverfolgt hat. Diese Zahl enth?lt also noch keine
Aussage ?ber eventuelle Fehler.
(*2): Hier wird angegeben, wieviele Diagnosezeilen der Heap Debugger
auszugeben hat. Im Idealfall sollte hier immer "0" stehen. Nicht
alle, aber die meisten Diagnosezeilen deuten auf einen Program-
mierfehler hin.
(*3): Hier wird eine laufende Nummer aller vom Programm vorgenommener
Allokationen ausgegeben. Bei Deallokationen (Flag "F") steht hier
nichts.
(*4): Hier wird die Adresse des allokierten bzw. deallokierten
Heapspeicherblocks ausgegeben. Diese Adresse kann von Programmlauf
zu Programmlauf variieren.
(*5): Hier wird die Gr??e des allokierten bzw. deallokieren Blocks
ausgegeben.
(*6): Die hier ausgegebenen Flags haben folgende Bedeutung
(Kombinationen sind m?glich):
keins: Es handelt sich um eine Allokation, zu der keine passende
Deallokation erfolgt ist.
"O" : Es handelt sich um die Daten einer Objektinstanz. Das ist
der Datenbereich, der vom Constructor eines Objektes
f?r die Felder des Objektes (und anderes) bei jeder neuen
Instanz angelegt wird. Als Aufrufer wird die Zeile mit
dem Word "BEGIN" des Construktors angegeben, bzw. die Zeile
mit dem Word "END" des Destructors bei Deallokationen.
"F" : Bei dieser Diagnosezeile geht es um eine Deallokation
(F=free). Was bei dieser Deallokation schiefgegangen ist,
wird mit einem der folgenden Flags angegeben.
Seite 9
"S" : Ein Heapspeicherblock wurde nicht mit der gleichen Block-
l?nge (S=size) deallokiert, mit der er allokiert wurde. In
diesem Falle wird dieses Flag sowohl in der Diagnosezeile
der Allokation als auch in der der Deallokation ausgegeben.
"M" : Zu einer Deallokation wurde keine passende Allokation
gefunden (M=mismatch). Das hei?t, da? versucht wurde, einen
Heapspeicherblock zu deallokieren, dessen Adresse nicht bei
einer vorangegangenen Allokation registriert worden ist.
Dieses Flag tritt nur zusammen mit dem Flag "F" auf.
(*7): Hier wird die Adresse der aufrufenden Programmstelle ausgegeben.
An dieser Programmstelle wurde die in der Diagnosezeile angegebene
Heap-Operation aufgerufen. Die Segmentadresse dieser Stelle ist
sowohl als virtuelle Segmentadresse (in eckigen Klammern "[]")
als auch aktuelle Segmentadresse angegeben. Die virtuelle Segment-
adresse wird vom Linker vergeben und ist die Adresse relativ zur
Adresse 0000. Die aktuelle Adresse wird beim Laden des Programms
vergeben und ist abh?ngig von der Stelle, an die das Programm in
den Speicher geladen wird. Die virtuelle Adresse findet sich im
MAP-File des Programms wieder. Die aktuelle Adresse kann von Pro-
grammlauf zu Programmlauf variieren.
(*8): Hier wird die Sourcecodestelle (Dateiname und Zeilennummer) ange-
geben, die sich die Aufrufer-Adresse bezieht. Voraussetzung daf?r
ist, da? ?berhaupt Debug-Informationen im EXE-File existieren.
Sind keine Debug-Informationen vorhanden, dann wird hier
"keine Info." angezeigt. Wenn zwar Debug-Informationen vorhanden
sind, aber die Sourcecodestelle zu der Aufrufer-Adresse trotzdem
nicht gefunden werden konnte, dann wird hier "?" angezeigt.
___ Besondere Meldungen im Heap Debugger Report ________________________
Folgende Meldungen k?nnen im Heap Debugger Report in Ausnahmef?llen auf-
treten:
"Programm durch HALT(nnn) gestoppt"
Diese Meldung erscheint, wenn das Programm gezielt mit dem Befehl
HALT(nnn) gestoppt wurde. Der Exitcode wird mit nnn angegeben.
"Laufzeitfehler nnn bei ssss:oooo, Datei: ________ Zeile: _____"
Wenn das Programm durch einen Laufzeitfehler abgebrochen wird, erscheint
diese Meldung. Als zus?tzliche, n?tzliche Information wird die
Programmstelle des Laufzeitfehlers (Quelldateiname und Zeilennummer)
ausgegeben, sofern diese Information verf?gbar ist.
"interner Fehler 203 im Heap Debugger aufgetreten"
Diese Meldung bedeutet, da? dem Heap Debugger zur Laufzeit nicht gen?-
gend Heapspeicher zur Verf?gung stand, um alle Heap-Operationen auf-
zeichnen zu k?nnen.
"Shareware-Limit ueberschritten!
Es wurden nur 50 pointer verarbeitet!"
Diese Meldung wird nur von der Sharewareversion ausgegeben und besagt,
da? das Sharewarelimit von 50 ?berwachten Allokationen zur Laufzeit
?berschritten worden ist.
Seite 10
___ Interpretation des Reports _________________________________________
Nat?rlich sollte man immer anstreben, am Ende eines Programmlaufs vom
Heap Debugger die Meldung "0 Debug-Eintraege vorhanden" gemacht zu
bekommen. Wenn der Heap Debugger w?hrend der gesamten Entwicklungszeit
einer Applikation kontinuierlich eingesetzt wird, dann l??t sich eine
nach einem Testlauf pl?tzlich auftauchende andere Meldung meist sehr
leicht mit der zuletzt vorgenommenen Programm?nderung in Zusammenhang
bringen.
Wenn die Sache einmal nicht so einfach ist, mu? man die Diagnose des
Heap Debuggers zun?chst einmal interpretieren, um dem Problem auf die
Schliche zu kommen.
Hierzu sollte man sich die folgenden Fragen stellen:
- Ist die Anzahl der Diagnoseeintr?ge immer gleich oder variiert diese
Anzahl ?
Soweit die Anzahl nicht variiert, handelt es sich offenbar um
einmalig vorkommende Fehler im Programm. Es gibt F?lle, bei denen
die Bezeichnung Fehler sogar etwas zu scharf gew?hlt ist. Manche
Programme legen n?mlich quasi-statische Variablen auf dem Heap an,
und geben diese dann am Ende nicht wieder frei. So ein Verhalten
ist zwar nicht sonderlich sch?n und sollte deshalb vermieden werden;
es hat andererseits aber auch keine schlimmen Konsequenzen.
- L??t sich das Anwachsen der Anzahl der Diagnosezeilen mit einer
bestimmten Funktion meines Programms in Zusammenhang bringen ?
Wenn die Anzahl w?chst, dann sollte man versuchen, den sich
offenbar wiederholenden Fehler auszumachen. Meistens ist das sehr
einfach, wenn n?mlich der Heap Debugger f?r mehrere Eintr?ge die
selbe Aufruferadresse ausgibt. Es handelt sich dann wohl um einen
Fehler, der immer dann zum Tragen kommt, wenn eine bestimmte
Programmfunktion ausgel?st wird. Solche Fehler sollte man auf jeden
Fall beseitigen, da sie den gef?rchteten "Ged?chtnisschwund" ausl?sen.
- Wurde in einzelnen Diagnosezeilen irgendein Flag eingetragen ?
Soweit nicht, handelt es sich bei den Diagnosen des Heap
Debuggers um Hinweise auf "klassische" Fehler, n?mlich auf das
unterlassene Freigeben "normaler" Heapspeicherbl?cke, die
mittels GetMem oder New angefordert wurden. Die Sourcecodereferenz
verweist auf die Stelle, an der diese Anforderung geschehen ist.
- Wurde in einzelnen Diagnosezeilen das Flag "O" eingetragen ?
Soweit ja, weist der Heap Debugger auf Verfehlungen im Zusammenhang
mit Objekten hin. Wird z.B. nur ein "O" eingetragen, dann handelt
es sich um nicht freigegebene Instanzdaten eines Objektes, welche
(im allgemeinen) mittels New in der OOP-Variante, n?mlich
New(ptr, constructor), angelegt worden sind. Die Sourcecodereferenz
deutet aber dann NICHT auf diese New-Anweisung, sondern auf die
Zeile BEGIN im betreffenden Constructor. Wenn man diesen ausgemacht
hat, mu? man ?berlegen, wo Instanzen dieses Objekttyps angelegt
werden und dort auf korrekte Freigaben pr?fen.
Seite 11
- Wurde in einzelnen Diagnosezeilen das Flag "F" eingetragen ?
Dieses Flag kommt nie allein. Es bedeutet (meistens), da? ein Deallo-
kationsfehler passiert ist. Au?er dem "F" ist immer entweder ein
"S" oder ein "M" gesetzt, was bedeutet, da? entweder eine Deallokation
mit einer falschen Blockl?nge aufgerufen worden ist, bzw. da? der
deallokierte Speicherblock an einer Adresse liegt, an der vorher
keine Allokation vorgenommen worden ist.
Solche Diagnosen sind entweder sehr schlimm oder sehr harmlos.
Der harmlose Fall ist im Abschnitt "MemAllocSeg" beschrieben. Wenn
diese Beschreibung nicht zutrifft, dann liegt wahrscheinlich ein
echter Fehler vor, der unbedingt gefunden werden mu?, weil er das
gesamte Programm (auch den Heap Debugger) zum Absturz bringen kann.
Letzteres kann passieren, wenn die Konsistenz der Heapverwaltung
nicht mehr gegeben ist. In so einem Fall k?nnen ?brigens auch Daten
auf dem Heap verst?mmelt werden.
___ Auffinden von Bugs _________________________________________________
Wenn der Heap Debugger zu seinen Diagnosen Sourcecodereferenzen ausgeben
konnte, dann ist das Auffinden von Bugs verh?ltnism??ig einfach.
Wenn die Sourcecodereferenz allerdings mit "?" angegeben wird, dann be-
findet sich die unter "Aufrufer" aufgef?hrte Adresse in einem Modul, das
nicht mit der Option "D+", also ohne Debuginformationen ?bersetzt worden
ist. Oft ist der Aufrufer dann in der Run-Time-Library zu finden.
Man sollte sich aber nicht zu dem Schlu? verleiten lassen, da? man f?r
den entsprechenden Fehler dann gar nicht verantwortlich ist und da? die
Run-Time-Library einen Bug hat. Wenn von Ihnen z.B. eine Allokation
mittels "NewStr" (Funktion der Run-Time-Library) vorgenommen wurde,
und der so angeforderte Heapspeicherblock wurde anschlie?end nicht
korrekt mit DisposeStr deallokiert, dann liegt der Fehler in Ihrem
Programmteil; als Aufrufer wird aber eine Zeile in der Funktion NewStr
genannt.
Viele Probleme dieser Art kann man l?sen, indem man die ganze
Run-Time-Library mit Debug-Option neu ?bersetzt. Das ist nur bei
BP7.0, nicht bei TP7.0 m?glich. Informationen hierzu bietet Borland
in der Datei \BP\RTL\README.
___ Arbeiten mit einem externen Debugger _______________________________
In hartn?ckigen F?llen kann man versuchen, einen Fehler mit Hilfe des
externen Debuggers einzugrenzen. Das ist besonders dann sinnvoll, wenn
man dem Heap Debugger trotz aller Bem?hungen keine Sourcecodereferenz
entlocken kann.
Im externen Debugger sollte man versuchen, auf die fragliche Programm-
stelle (die Aufruferadresse) einen Breakpoint zu setzen.
Beachten Sie hierzu den Unterschied zwischen der virtuellen und der
aktuellen Segmentadresse, die der Heap Debugger ausgibt.
Seite 12
Achtung: Die aktuelle Segmentadresse eines Aufrufers kann sich von
Programmlauf zu Programmlauf verschieben. Nach dem Laden des Debuggers
wird sie sich sogar sehr wahrscheindlich verschieben. Lassen Sie daher
Ihr Programm mit geladenem Debugger einmal oder mehrmals laufen, ohne
einen Breakpoint zu setzen. Verwenden sie die zuletzt ausgegebene
aktuelle Segmentadresse, um den Breakpoint zu setzen. Sie setzen einen
Breakpoint auf eine von Hand eingegebene Adresse mit der Funktion
"Breakpoints->At...". Geben Sie einfach die Adresse ein und beginnen Sie
die Segmentadresse UND die Offsetadresse jeweils mit "$" f?r hexadezi-
male Notation.
Wenn Sie Ihr Programm dann starten und einen Breakpoint erreichen,
versuchen Sie das Programm ab dieser Stelle in Einzelschritten fortzu-
setzen, bis Sie zu einer Stelle des Programms kommen, die Ihnen bekannt
ist.
___ Compilerschalter in USEHDEB ________________________________________
In die Unit UseHDeb wurden bereits einige Compilerschalter eingef?hrt,
die die Anpassung an besondere Anforderungen erleichtern sollen. Wir
hoffen, da? damit die allermeisten Anpassungsprobleme zu l?sen sind, so
da? dem Anwender eine weitergehende Ver?nderung des Sourcecodes erspart
bleibt.
Der Schalter "USE_SHAREWARE":
Wenn dieser Schalter aktiv ist, dann wird der Heap Debugger in einer der
Units "HDEB7S.TP?" benutzt. Wenn er ausgeschaltet ist, dann wird eine
der Units "HDEB7F.TP?" eingebunden. Letztere stellt die Vollversion des
Heap Debuggers dar und kann nat?rlich nur verwendet werden, wenn die
Software registriert worden ist. Dieser Compiler ist bei Lieferung der
Shareware- bzw. der Vollversion schon richtig eingestellt und mu? also
in der Regel nicht ver?ndert werden.
Der Schalter "GERMAN_LANG":
Wenn dieser Schalter aktiv ist, dann wird der Heap Debugger Report in
deutscher Sprache ausgegeben, sonst in Englisch.
Der Schalter "GETDEBUGINFO":
Wenn dieser Schalter aktiv ist, dann wird bei der Reportausgabe ver-
sucht, auf die Debug-Informationen im EXE-File zuzugreifen, um Dateina-
men und Zeilennummer zu jeder Diagnosezeile zu ermitteln. Dieser Schal-
ter sollte normalerweise aktiv bleiben.
Der Schalter "REPORT_TO_FILE":
Wenn dieser Schalter aktiv ist, dann wird die Reportausgabe der Unit
UseHDeb in eine Datei umgeleitet. Der Name dieser Datei wird mit der
Konstanten DumpFileName festgelegt und ist auf "HEAPDEB.DMP" voreinge-
stellt, kann aber ver?ndert werden. Die Datei wird mit jeder Reportaus-
gabe erweitert. Bitte beachten Sie: Wenn der Heap Debugger aus irgendei-
nem Grund nicht initialisiert wurde und der Schalter "REPORT_TO_FILE"
aktiviert ist, dann wird das Programm ohne Ausgabe einer Meldung (auch
nicht in die Datei) mit dem Kommando "HALT" gestoppt.
Seite 13
Der Schalter "SWITCH_TO_LASTMODE":
Wenn dieser Schalter aktiv ist, dann wird vor der Reportausgabe der Unit
UseHDeb mit dem Kommando "Textmode(LastMode)" in den Videomodus zur?ck-
geschaltet, der beim Start des Programms aktiv war. Dies kann n?tzlich
sein, wenn das Hauptprogramm z.B. in einen vom BIOS nicht unterst?tzten
Grafikmodus umschaltet oder Textfarben so manipuliert, da? die Report-
ausgabe nicht lesbar ist. Dieser Schalter hat unter Windows keine Aus-
wirkung.
Beispiel f?r das Ein- und Ausschalten eines Schalters:
aktiv: "{$DEFINE GERMAN_LANG}"
inaktiv: "{not $DEFINE GERMAN_LANG}"
HEAP DEBUGGING IM DETAIL _______________________________________________
___ Overlays ___________________________________________________________
Sie k?nnen den Heap Debugger auch innerhalb von Programmen nutzen, die
von Overlayprogrammierung Gebrauch machen. Die Units USEHDEB und HDEB7?
d?rfen allerdings nicht als Overlays geladen werden.
___ DLLs _______________________________________________________________
Eine DLL kann man mit dem Heap Debugger behandeln wie ein normales, ei-
genst?ndiges Programm. Wenn ein Programm, das den Heap Debugger verwen-
det, zur Laufzeit eine DLL einbindet, dann ist der Heap Debugger f?r
diese DLL nicht wirksam. Umgekehrt kann eine DLL den Heap Debugger ver-
wenden, ohne da? dadurch die Heap-Operationen im Hauptprogramm ?berwacht
werden. Wird sowohl in eine DLL alsauch in das Hauptprogramm der Heap
Debugger eingebunden, so werden zum Programmende zwei Reporte ausgege-
ben.
Das Einbinden des Heap Debuggers in eine DLL erfolgt demgem?? auch wie
bei einem normalen Programm: In der Hauptquelldatei der DLL (mit der
?berschrift "library") wird die Unit UseHDeb als erste in die uses-
Klausel eingef?gt.
Der Exit-Code der Unit UseHDeb (mit der Reportausgabe) wird beim Beenden
der DLL durchgef?hrt. Wann ist das ? Die DLL wird normalerweise beendet,
wenn auch das Hauptprogramm, das die DLL geladen hat, beendet wird. Es
gibt allerdings Ausnahmen. Wenn man das Hauptprogramm mit dem externen
Debugger ausf?hrt, so wird die DLL nicht bei Programmende abgeschlossen,
sondern beim Verlassen des Debuggers, was dann aus unerfindlichen Gr?n-
den h?ufig zu einem Absturz des Rechners f?hrt. Es empfiehlt sich daher
sehr, eine DLL, die den Heap Debugger einbindet, zur Laufzeit des Haupt-
programms gezielt mit der Anweisung "FreeLibrary" zu beenden, wodurch
der Exit-Code der Unit UseHDeb f?r die DLL ausgef?hrt und somit der Re-
port ausgegeben wird.
Das bisher Gesagte gilt f?r DLLs unter DOS und unter Windows gleicher-
ma?en.
Seite 14
Unter Windows ergibt sich aber noch ein zus?tzliches Problem: Die Re-
portausgabe, die von der Unit UseHDeb unter Windows ja in ein WinCrt-
Fenster vorgenommen wird, klappt bei einer DLL nicht: Die Folge des Ver-
suches, eine Reportausgabe aus einer DLL heraus in ein WinCrt-Fenster
vorzunehmen, ist in aller Regel entweder ein Laufzeitfehler oder das
v?llige Ausbleiben jeder Ausgabe. Unter DOS gibt es diese Probleme
nicht.
Es ist unter Windows bei Einsatz des Heap Debuggers in einer DLL also
unbedingt notwendig, die Ausgaben der Unit UseHDeb in eine Datei umzu-
leiten. Hierf?r wurde der Schalter "REPORT_TO_FILE" vorbereitet (siehe
hierzu "Compilerschalter in USEHDEB").
___ Programminstanzen (Windows) ________________________________________
Wenn unter Windows ein Programm, das den Heap Debugger einbindet, in
mehreren Instanzen gestartet wird, so wird nur f?r die erste Instanz der
Heap Debugger installiert. Folgende Instanzen nutzen automatisch den
schon installierten Heap Debugger mit. Die Ausgabe des Reports erfolgt
erst nach Beenden der letzten aktiven Instanz des Programms, und der Re-
port beinhaltet alle Heap-Operationen, die in anderen Instanzen des sel-
ben Programms vorgenommen wurden, ohne das die verursachenden Instanzen
in dem Report voneinander unterschieden werden k?nnen. Um die ?bersicht-
lichkeit zu wahren, sollten also m?glichst nicht mehrere Instanzen aus-
gef?hrt werden.
___ Interrupts ________________________________________________________
Der Heap Debugger ben?tigt f?r seine Arbeit drei eigene Softwareinter-
rupts. Das hei?t, da? der Heap Debugger bei der Installation drei freie
Interruptvektoren belegt und diese bei Programmende wieder restauriert.
Der Heap Debugger sucht sich die freien Softwareinterrupts selbst aus,
und zwar im Bereich 78h bis FFh. Aus diesem Bereich k?nnen gezielt ein-
zelne Interrupts vom Programmierer ausgeschlossen werden, indem in der
Unit UseHDeb.PAS die Anweisung "HeapDebInit([])" ver?ndert wird. In der
als Parameter angegebenen leeren Menge kann eine Menge von Interruptnum-
mern definiert werden, die vom Heap Debugger nicht benutzt werden
sollen. Eine ?nderung dieses Aufrufes in "HeapDebInit([$F0..$FF])" w?rde
z.B. die Interruptvektoren F0h bis FFh f?r die Benutzung durch den Heap
Debugger ausschlie?en und somit f?r das Hauptprogramm freihalten.
___ Stabilit?t und Performance _________________________________________
Wie schon erl?utert sollte der Heap Debugger nicht als Bestandteil fer-
tiger Applikationen eingesetzt werden. Der Heap Debugger sollte aus-
schlie?lich als Debuggingwerkzeug in der Entwicklungsphase verwendet
werden.
Der permanente Einsatz des Heap Debuggers w?hrend der Softwareentwick-
lung kann die Stabilit?t der entwickelten Software erheblich verbessern
und die Entwicklungszeit verk?rzen.
Es ist jedoch nicht auszuschlie?en, da? der Heap Debugger in der Ent-
wicklungsphase eine potentielle Ursache f?r Programmabst?rze sein kann,
auch wenn dies von uns bisher nicht beobachtet werden konnte. Folgende
Tatsachen sollten beachtet werden:
Seite 15
- Der Heap Debugger ?berwacht nicht nur die korrekte Verwendung des
Heapspeichers. Er ben?tigt auch selbst Heapspeicher f?r diese Aufgabe.
Wenn ein Programm zeitweise eine gro?e Anzahl von Heapspeicherbl?cken
allokiert, so kann der zus?tzliche Speicherbedarf des Heap Debuggers
erheblich sein. Mit zus?tzlichen 24 Byte je allokiertem (und noch
nicht wieder deallokiertem) Speicherblock sollte gerechnet werden.
- Die Ausf?hrung des Heap Debuggers erfordert zus?tzlich Platz auf dem
Stack, und zwar sowohl bei der Ausf?hrung von Speicheroperationen als-
auch bei der Ausgabe der Reports in der Exitprozedur der Unit UseHDeb.
Hier ist zu beachten, da? teilweise keine ?berpr?fung des Stacks m?g-
lich ist, so da? ein zu klein dimensionierter Stack ein Programm zum
Absturz bringen kann.
- Bei massiven Fehlern des Applikationsprogrammierers bei dem Umgang mit
Heapspeicher kann der Einsatz des Heap Debuggers, der wie gesagt auch
selbst mit Heapspeicher arbeitet, den Absturz eines Programmes sogar
erst ausl?sen, was, in einer zuf?llig anderen Konstellation, ohne den
Heap Debugger vielleicht nicht passiert w?re. Solche Abst?rze k?nnen
zum Beispiel dann passieren, wenn die Applikation versucht, einen vor-
her gar nicht allokierten Speicherbereich freizugeben. In diesem Fall
ist ein Programmabsturz als klares Indiz f?r einen Programmierfehler
jedenfalls einem tr?gerischen fehlerfreien Programmablauf vorzuziehen.
- Der Heap Debugger braucht f?r seine Arbeit zus?tzliche Rechenzeit. Je
mehr Speicherbl?cke allokiert werden, um so mehr steigt der Zeitbedarf
des Heap Debuggers, insbesondere beim Wiederfreigeben von Speicher.
Diese Performanceeinbu?e wird aber allenfalls bei sehr zeitkritischen
Anwendungen irgendwie sp?rbar sein.
- Der Heap Debugger ben?tigt, wie schon im vorherigen Abschnitt erw?hnt,
f?r seine Arbeit drei freie Softwareinterrupts, deren Vektoren er zum
Anfang des Programms auf eigene Routinen umlenkt und zum Ende des Pro-
gramms wieder restauriert. Wenn ein Programm durch einen fatalen Feh-
ler so abrupt beendet wird, da? die Exitprozedur von UseHDeb nicht
mehr durchlaufen wird, dann werden auch diese Interruptvektoren nicht
mehr wieder auf ihre alten Werte eingestellt. Wenn anschlie?end gela-
dene Programme aber von korrekten Werten in diesen Vektoren abh?ngig
sind, so kann dies zu Problemen f?hren. Wenn sich solche Abst?rze sehr
h?ufig wiederholen, dann kann der Heap Debugger irgendwann keine
freien Interrupts mehr finden und kann nicht gestartet werden.
___ Eingriffsm?glichkeiten f?r den Programmierer _______________________
Es ist f?r einige F?lle denkbar, da? ein Programmierer ?nderungen am
Heap Debugger vornehmen m?chte, um z.B. die Reportausgabe seinen eigenen
Vorstellungen anzupassen. Aus diesem Grunde wird die Unit UseHDeb im
Quellcode mitgeliefert. Programm?nderungen d?rfen nur an dieser Unit und
nur zu eigenen, nichtkommerziellen Zwecken vorgenommen werden.
Dar?berhinaus bietet das Interface der Unit HDeb7?.TP? folgende typi-
sierte Konstanten an, die zur Laufzeit eines Programms ver?ndert werden
k?nnen:
Seite 16
1) SuspendHeapdeb : Boolean = false;
Wird diese Konstante zur Laufzeit des Hauptprogramms auf TRUE gesetzt,
so werden anschlie?end keine Heap Operationen vom Heap Debugger mehr
aufgezeichnet. Nach R?ck?nderung des Wertes auf FALSE arbeitet der Heap
Debugger wieder normal. Dies kann z.B. n?tzlich sein, um quasi statische
Allokationen, die sonst bei jeder Reportausgabe des Heap Debuggers auf-
gef?hrt werden, f?r den Heap Debugger "unsichtbar" zu machen und dadurch
einen "sauberen" Report zu erm?glichen.
2) RecordZeroSize : Boolean = false;
Solange diese Konstante den Wert FALSE hat, werden Allokationen und De-
allokationen mit der L?nge Null vom Heap Debugger ignoriert. Weil solche
Operationen reine Sch?nheitsfehler sind und unseres Wissens keinen Scha-
den anrichten k?nnen, ist diese Konstante auf FALSE voreingestellt.
3) RTEOnWrongSizedFree : Byte = 0;
Wenn in diese Konstante ein anderer Wert als Null geladen wird, dann
wird bei jeder Deallokation, die nicht die gleiche L?nge wie die zuge-
h?rige Allokation aufweist (Flag "S"), sofort ein Run-Time-Error ausge-
l?st. Die Nummer des Run-Time-Errors wird durch diese Konstante
bestimmt.
4) RTEOnUnknownFree : Byte = 0;
Wenn in diese Konstante ein anderer Wert als Null geladen wird, dann
wird bei jeder Deallokation, zu der keine passende Allokation (gleiche
Anfangsadresse des Heapspeicherblocks) gefunden werden kann (Flag "M"),
sofort ein Run-Time-Error ausgel?st. Die Nummer des Run-Time-Errors wird
durch diese Konstante bestimmt.
BEKANNTE EINSCHR?NKUNGEN UND PROBLEME __________________________________
___ Mark/Release _______________________________________________________
Von der Verwendung der Befehle Mark und Release erh?lt der Heap Debugger
keinerlei Kenntnis und kann sie also auch nicht ber?cksichtigen. Dar?ber
hinaus kann die Anweisung Release den Heap Debugger erheblich st?ren
(bis hin zum Programmabsturz), weil dadurch eventuell auch Aufzeichnun-
gen des Heap Debuggers verworfen werden, ohne da? der Heap Debugger die-
ses erkennen kann.
Allerdings werden die Befehle Mark und Release fast gar nicht mehr ver-
wendet, denn sie bringen, unabh?ngig von der Unvertr?glichkeit mit dem
Heap Debugger, noch eine Reihe anderer Probleme mit sich. Wahrscheinlich
sind sie in der aktuellen Version des Compilers nur noch aus Kompatibi-
lit?tsgr?nden implementiert. Von der Verwendung von Mark und Release ist
also allgemein abzuraten. Mark und Release stehen nur unter DOS zur Ver-
f?gung.
Seite 17
___ MemAllocSeg ________________________________________________________
Die Funktion MemAllocSeg in der Unit Memory (unter Windows: OMemory)
stellt den Heap Debugger vor ein gro?es Problem: Die Aufgabe dieser
Funktion ist es, einen Heapspeicherbereich anzufordern, dessen Anfangs-
adresse genau auf dem Anfang eines Speichersegmentes liegt, also die
Offsetadresse 0000 hat. Um dieses zu erreichen, greift die Funktion
MemAllocSeg tief in die Trickkiste, wobei wir zwischen den verschiedenen
Zielplattformen unterscheiden m?ssen:
Real Mode:
Um garantiert einen Heapspeicherbereich mit der Offsetadresse 0000 allo-
kieren zu k?nnen, reserviert die Funktion MemAllocSeg mittels GetMem zu-
n?chst einen etwas gr??eren Bereich, um anschlie?end sofort wieder einen
kleinen Teil davon (n?mlich 8 Bytes), die entweder am Anfang oder am
Ende des gerade allokierten gr??eren Bereichs liegen, mittels FreeMem
freizugeben. Hier wird also etwas getan, was zwar in engen Grenzen er-
laubt, aber verp?nt ist: Der Heap Debugger "beobachtet" diese Operatio-
nen und wird sie sp?ter in seinem Report ausgeben. Das kann dann z.B. so
aussehen:
program TEST;
uses UseHDeb, Memory;
var p: pointer;
begin
{...}
p := MemAllocSeg(100);
FreeMem(p, 100);
end.
HEAP-DEBUGGER-DIAGNOSE:
1 Pointer wurden registiert
3 Debug-Eintraege vorhanden
auflisten (J/N) ? j
Nr Pointer Size Flags Aufrufer Datei Zeile
1 1A4D:0000 112 S 020B[1438]:001F MEMORY.PAS 327
1A53:0008 8 F M 020B[1438]:00D5 MEMORY.PAS 355
1A4D:0000 100 FS 0000[122D]:003A TEST.PAS 7
Oder so:
HEAP-DEBUGGER-DIAGNOSE:
1 Pointer wurden registiert
3 Debug-Eintraege vorhanden
auflisten (J/N) ? j
Nr Pointer Size Flags Aufrufer Datei Zeile
1 1531:0008 112 S 020C[0F1A]:001F MEMORY.PAS 327
1531:0008 8 FS 020C[0F1A]:00D5 MEMORY.PAS 355
1532:0000 100 F M 0000[0D0E]:004A TEST.PAS 7
Der Programmierer ist wohl oder ?bel gezwungen, solche nicht ganz ast-
reinen Heap-Operationen zu dulden und derartige Diagnosen des Heap
Debuggers zu ignorieren.
Seite 18
(Die Referenz auf die Sourcecodestellen in der Unit Memory werden nur
dann ausgegeben, wenn diese Unit mit der Option $D+ ?bersetzt worden
ist.)
Protected Mode (DOS/DPMI):
Hier hat es die Funktion MemAllocSeg etwas einfacher als im Real Mode:
Sie ruft einfach die Funktion "MemAllocateBlock" auf, welche von der
RTM.EXE zur Verf?gung gestellt wird und eine entsprechene DPMI-Funktion
darstellt. Dadurch wird ein Heapspeicherblock allokiert, der garantiert
bei der Offsetadresse 0000 beginnt. Wie schon im Abschnitt "Globaler und
lokaler Heap" beschrieben, erh?lt der Heap Debugger von diesem Vorgang
keine Kenntnis. Die Freigabe des so allokierten Heapspeicherblocks wird
jedoch ?berlicherweise mit der Funktion FreeMem vorgenommen, wovon der
Heap Debugger s
##### To see the rest of this file, please download it #####