[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]
{
From: dmurdoch@mast.queensu.ca (Duncan Murdoch)
>
>Anyhow, what this program is doing (among other things) is reading data from
>an ASCII file when commanded to, one line at a time, and plotting it on the
>screen. My problem is, when you return to the main menu, a bit of the RAM
>has been used. If you call up a couple of plots in a row, eventually you
>run out of RAM and crash. And I'm having a devil of a time trying to figure
>where the memory is going.
This is one of the harder kinds of error to track down. The way I do it is
as follows:
1. Throughout program development, I use a debugging unit that warns me if
anything is left on the heap when the program terminates. If there is, I
immediately track it down and fix it. The error is probably in the new
part, and that helps to find it.
2. To prevent errors, I program in a very structured way: every allocation
has a matching de-allocation, preferable within a dozen or two lines of
it so they're both on screen at once and I can see that they match.
3. If the preventive methods don't work, I have to track down the bugs. I
have a routine that can print heap usage when I want. I print all the heap
that's used at the end of the program (should be none!), and try to
recognize where the stuff came from. If it's strings, it's easy, but if
it's binary data, it's hard. If necessary I trace through the program until
I see one of those parts get allocated.
I've attached my heap routine below, but it won't compile for you without a
few utility routines from TurboPower's Object Professional library (and
some others of mine). Hopefully it'll still be useful for you and you can
write the other parts yourself.
Duncan Murdoch
}
unit heap;
{ This unit does integrity checks on the TP 6.0 heap }
interface
uses standard,opinline,opstring,dump;
function heapokay:boolean;
procedure showfreelist(var where:text;msg:string);
{ Prints the free list }
procedure showheapused(var where:text;msg:string);
{ Prints the heap usage }
type
PFreeRec = ^TFreeRec;
TFreeRec = record
next: PFreeRec;
size: Pointer;
end;
implementation
function Ordered(p1,p2:pointer):boolean;
{ Tests whether p1 <= p2 }
begin
Ordered := PtrToLong(p1) <= PtrToLong(p2);
end;
function Normed(p:pointer):boolean;
{ Checks whether p is a normalized pointer }
begin
case ofs(p^) of
0..$F : Normed := true;
else Normed := false;
end;
end;
function heapokay:boolean;
procedure error(msg:string);
begin
writeln(stderr,msg);
heapokay := false;
halt(99);
end;
type
PFreeRec = ^TFreeRec;
TFreeRec = record
next: PFreeRec;
size: Pointer;
end;
var
FreeRec : PFreeRec;
begin
if not Normed(HeapOrg) then
error('HeapOrg bad!');
if not Normed(FreeList) then
error('FreeList bad!');
if not Normed(HeapPtr) then
error('HeapPtr bad!');
if not Normed(HeapEnd) then
error('HeapEnd bad!');
if not Ordered(HeapOrg,FreeList) then
error('HeapOrg > FreeList');
if not Ordered(FreeList,HeapPtr) then
error('FreeList > HeapPtr');
if not Ordered(HeapPtr,HeapEnd) then
error('HeapPtr > HeapEnd');
FreeRec := FreeList;
while PtrToLong(FreeRec) < PtrToLong(HeapPtr) do { Walk the free list }
begin
if not Normed(FreeRec^.next) then
error('Bad next in free record '+HexPtr(FreeRec));
if not ordered(FreeRec,FreeRec^.next) then
error('self > next in free record '+HexPtr(FreeRec));
if not ordered(AddLongToPtr(FreeRec,PtrToLong(FreeRec^.size)),
FreeRec^.next) then
error('Bad size in free record '+HexPtr(FreeRec));
if FreeRec = FreeRec^.Next then
error('Self pointer in free record '+HexPtr(FreeRec));
FreeRec := FreeRec^.Next;
end;
if FreeRec <> HeapPtr then
error('Bad last free block');
heapokay := true;
end;
function addtopointer(p:pointer;incr:longint):pointer;
{ Adds increment to pointer, only normalizes if necessary }
begin
if ofs(p^) + incr > 65535 then
addtopointer := AddLongToPtr(p,incr)
else
addtopointer := AddWordToPtr(p,incr);
end;
procedure showfreelist(var where:text;msg:string);
{ Prints the free list }
var
FreePtr : PFreerec;
Free,Total:longint;
begin
writeln(where,msg);
writeln(where,' Start Stop Size free');
FreePtr := PFreeRec(@FreeList);
Total := 0;
repeat
Free:=PtrToLong(Freeptr^.Size);
inc(Total,Free);
if Free <> 0 then
writeln(where, HexPtr(FreePtr), ' ', HexPtr(AddToPointer(FreePtr,Free)),
' ',Free:6);
FreePtr := FreePtr^.next;
until FreePtr = HeapPtr;
Free := PtrDiff(HeapEnd,HeapPtr);
inc(Total,Free);
writeln(where, HexPtr(HeapPtr), ' ', HexPtr(HeapEnd),
' ',Free:6);
writeln(where, 'Total':8,'':14, Total:6);
end;
procedure showheapused(var where:text;msg:string);
{ Prints what's been used on the heap }
var
FreePtr : PFreerec;
UsedPtr : Pointer;
Used : longint;
Total: longint;
begin
writeln(where,msg);
writeln(where,' Start Stop Size used Data');
FreePtr := FreeList;
UsedPtr := HeapOrg;
total := 0;
while FreePtr <> HeapPtr do
begin
Used := PtrDiff(UsedPtr,FreePtr);
inc(Total,Used);
if used <> 0 then
begin
write(where, HexPtr(UsedPtr), ' ', HexPtr(AddToPointer(UsedPtr,Used)),
' ',Used:6,' ');
dumpbothshort(where, UsedPtr^, 0, 8);
end;
UsedPtr := AddLongToPtr(FreePtr,PtrToLong(FreePtr^.size));
if FreePtr <> HeapPtr then
FreePtr := FreePtr^.next;
end;
Used := PtrDiff(HeapPtr,UsedPtr);
inc(Total,used);
if used <> 0 then
begin
write(where, HexPtr(UsedPtr), ' ', HexPtr(AddToPointer(UsedPtr,Used)),
' ',Used:6,' ');
dumpbothshort(where, UsedPtr^, 0,8);
end;
writeln(where, 'Total':8,'':14, Total:6);
end;
end.
[Back to MEMORY SWAG index] [Back to Main SWAG index] [Original]