Article 698 of comp.sys.apple2.programmer:
Path: news.uoregon.edu!cie.uoregon.edu!nparker
From: nparker@cie.uoregon.edu (Neil Parker)
Newsgroups: comp.sys.apple2.programmer
Subject: Re: Where are the handles?? Hmmm....
Date: 24 Aug 1993 09:48:43 GMT
Organization: The Universal Society for the Prevention of Reality
Lines: 47
Message-ID: <25co5r$2nb@pith.uoregon.edu>
References: <CC82Ay.Btu@bernina.ethz.ch>
NNTP-Posting-Host: cie.uoregon.edu

In article <CC82Ay.Btu@bernina.ethz.ch> GUDATH@EZINFO.VMSMAIL.ETHZ.CH
(Bright Software) writes:
>I was and am wondering how one can build a complete list of memory blocks. I
>need to know the absolute addresses and the IDs of these blocks (and perhaps
>the handles)...
> 
>Is that possible somehow???? I think NiftyList got such a function, and
>SuperConvert, too...how did they do that???

Yes, it's possible.  It's not documented, but there are enough things that
depend on it (the Memory Peeker CDA, the Memory Mangler CDA, Nifty List,
etc.) that it's not likely to be changed.

The Memory Manager keeps three lists of handles--the Used List (where all
the handles currently in use reside), the Purge List (which is the limbo
where handles go after you call PurgeHandle), and the Free List (where dead
handles go after you kill them with DisposeHandle).

The pointer the first element of the Used List is at $E1/1600 (4 bytes),
the pointer to the Purge List is at $E1/1604, and the pointer to the Free
List is at $E1/1608.  Each list is a doubly-linked list whose elements have
the following structure:

     struct Handle {
          Pointer Addr;        /* Master pointer to block of memory */
          Word Attr;           /* Handle attributes */
          Word ID;             /* UserID of handle's owner */
          long Size;           /* Length (in bytes) of block */
          struct Handle *Prev; /* Pointer to previous handle structure */
          struct Handle *Next; /* Pointer to next handle structure */
     };

The first element of the list has its Prev pointer set to NIL, and the last
element of the list has its Next pointer set to NIL.

The Memory Manager keeps the Used List sorted in order of increasing Addr.
This makes it possible to find unallocated blocks of memory by walking the
Used List and comparing curHandle.Addr+curHandle.Size to
curHandle.Next->Addr...if they don't match, then you've found a "hole"--the
memory from the current handle's Addr+Size to the next handle's Addr is
free.

               - Neil Parker
--
Neil Parker                 No cute ASCII art...no cute quote...no cute
nparker@cie.uoregon.edu     disclaimer...no deposit, no return...
parker@corona.uoregon.edu   (This space intentionally left blank:           )