You type (cdr'(a b c)) the system returns the list (b c) but neither this list or the rest of the tree is used any longer.
When you have the function foo defined by:(defun foo (x y) (setq x '(a b c)) (setq y '(e f g)))
The lists are all local and once the function completes its run neither list can be accessed again.
The problem with this is that lists use large amounts of memory quickly and without some way to reclaim the memory the program would use all of the memory available without doing much.
One other problem. All information connected with an atom (function definitions, property lists, and global values) must be maintained. If the following is executed:
(setq x '(a b c))
The list (a b c) is now attached to the atom node for x. Notice that that list is part of a larger list (setq x '(a b c)) which is translated to (setq x (quote (a b c)))). All of this list except for the (a b c) is garbage.
How do we collect garbage? First how can we allocate memory in such a way that we override the system and make garbage collection possible.
First we know that the hash table (or other global variable lookup table) has access to all permanent list nodes. This is because the atoms are held in the table and have pointers to lists that describe their various properties. This means that any list that is not garbage can be traversed from the hash table (demonstrate)
Now we only need to be able to search all of memory (that we are using) to see which nodes are marked and which aren't. Those that aren't are put back into the free memory list.
One other problem. Some systems only allow allocation of blocks of a specified maximum size. To overcome this problem you may want to create a linked list of memory blocks.
All list nodes are the same size, and consist of classification byte and two pointers
CLASSTYPE = (ATOM, ACTIVE, DOT, LIST, FULLWORD, NUMTYPE);
SPTR = ^NODE;(* POINTER TO AN S-EXPRESSION*)
NODE = record
case CLASS : CLASSTYPE of
ACTIVE, DOT, LIST: (
LEFT: SPTR; (* CAR OF NODE *)
RIGHT: SPTR
); (* CDR OF NODE *)
ATOM: (
PLIST: SPTR; (* Plist of atom*)
LConst: SPTR; (* value of the atom *)
PName: SPTR; (* holds list of print name*)
FunVal: SPTR (* holds pointer to functional value if any *)
);
FULLWORD: (
NAME: Pstring {This used to be a string}
);
NUMTYPE: (
VAL: INTEGER
);
end;(*NODE*)
The storage class
StorageArray = array[1..maxmem] of NODE;
MemoryPtr = ^MemoryBlock;
MemoryBlock = record
Block: StorageArray;
Next: MemoryPtr
end;
Initialize the memory block and the FreeList
procedure MemInitialize;
var
i: integer;
begin
LispFree := 1;
LispFreeList := nil;
LispLastFree := nil;
new(FirstBlock);
CurrentBlock := FirstBlock;
CurrentBlock^.Next := nil;
NumberFree := MaxMem
end; (* MemInitialize *)
Mark all of the nodes in use.
procedure PlistCheck (p: SPTR);
begin (* PlistCheck*)
if (p <> nil) then
if (p^.CLASS = LIST) or (p^.class = dot) then
begin
p^.CLASS := ACTIVE;
PlistCheck(p^.LEFT);
PlistCheck(p^.RIGHT)
end
end;(* PlistCheck *)
procedure Sweep;
var
I: integer;
Temp: SPTR;
begin (* Sweep*)
for I := 0 to ONELESS do
begin
Temp := OBLIST[I];
while Temp <> nil do
begin
Temp^.CLASS := ACTIVE;
PlistCheck(Temp^.LEFT^.PLIST);
PlistCheck(Temp^.Left^.LConst);
PlistCheck(Temp^.Left^.FunVal);
{install if names become lists }
{PlistCheck(Temp^.Left^.PName);
Temp := Temp^.Right
end
end;
PlistCheck(TRLIST);
end; (* Sweep *)
Once all of the global nodes are marked active, Collect the rest into a linked list.
procedure Garbage;
begin
Sweep;
Gather;
end;(* Garbage *)
procedure CollectBlock (var B: StorageArray; BlockSize: Integer);
var
i: integer;
begin (* CollectBlock*)
for i := 1 to BlockSize do
begin
if B[i].class = Active then
B[i].class := List
else
begin
if LispFreeList = nil then
LispFreeList := @B[i]
else
LispLastFree^.Right := @B[i];
LispLastFree := @B[i];
Inc(NumberFree)
end
end;
LispLastFree^.Right := nil
end;(*CollectBlock *)
procedure Gather;
var
GatherBlock: MemoryPtr;
begin (* Gather *)
LispFreeList := nil;
LispLastFree := nil;
NumberFree := 0;
GatherBlock := FirstBlock;
while GatherBlock <> CurrentBlock do
begin
CollectBlock(GatherBlock^.Block, MaxMem);
GatherBlock := GatherBlock^.Next
end;
CollectBlock(CurrentBlock^.Block, (LispFree - 1));
NumberFree := NumberFree + (MaxMem - LispFree);
if NumberFree < 2 * TooFewNodes then
NewBlock
end;(* Gather *)