1.2. Fundamentos y conceptos teóricos
1.2.2. Variable dependiente: Desempeño laboral
1.2.2.1. Diseño organizacional
If none of the questions stated at the beginning of Section 3.3 lead to sucient reduction in the lifetime and visibility of objects, the last resort is to allocate storage on a heap: The objects are allocated storage arbitrarily within an area of memory. Their addresses are determined at the time of allocation, and they can only be accessed indirectly. Examples of objects requiring heap storage are anonymous objects such as those created by the Pascal
new
function and objects whose size changes unpredictably during their lifetime. (Linked lists and the exible arrays of ALGOL 68 belong to the latter class.)Notice that the static and dynamic chain pointers were the only interconnections among the activation records discussed in Section 3.3.2. The use of a stack storage discipline is not required, but simply provides a convenient mechanism for reclaiming storage when a contour is no longer relevant. By storing the activation records on a heap, we broaden the possibilities for specifying the lifetimes of objects. This is the way in which the uniform retention strategy mentioned at the end of Section 2.5.2 is implemented. Storage for an activation record is
3.3 Storage Management 61 released only if the program fragment (block, procedure, class) to which it belongs has been left and no pointers to objects within this activation record exist.
Heap allocation is particularly simple if all objects required during execution can t into the designated area at the same time. In most cases, however, this is not possible. Either the area is not large enough or, in the case of virtual storage, the working set becomes too large. A detailed discussion of heap storage management policies is beyond the scope of this book (see Section 3.5 for references to the relevant literature). We shall only sketch three possible recycling strategies for storage and indicate the support requirements placed upon the compiler by these strategies.
If a language provides an explicit `release' operation, such as Pascal's
dispose
or PL/1'sfree
, then heap storage may be recycled by the user. This strategy is simple for the compiler and the run-time system, but it is unsafe because access paths to the released storage may still exist and be used eventually to access recycled storage with its earlier interpretation. The release operation, like the allocation operation, is almost invariably implemented as a call on a support routine. Arguments that describe the size and alignment of the storage area must be supplied to these calls by the compiler on the basis of the source type of the object. Automatic reclamation of heap storage is possible only if the designers of a language have considered this and made appropriate decisions. The key is that it must be possible to determine whether or not a variable contains an address. For example, only a variable of pointer type may contain an address in a Pascal program. A special value,nil
, indicates the absence of a pointer. When a pointer variable is created, it could be initialized tonil
. Unfortunately, Pascal also provides variant records and does not require such records to have a tag eld indicating which variant is in force. If one variant contains a pointer and another does not, it is impossible to determine whether or not the corresponding variable contains a pointer. Detailed discussion of the tradeos involved in such a decision by a language designer is beyond the scope of this text.Storage can be recycled automatically by a process known as garbage collection, which operates in two steps:
Mark. All accessible objects on the heap are marked as being accessible.
Collect. All heap storage is scanned. The storage for unmarked objects is recycled, and all marks are erased.
This has the advantage that no access paths can exist to recycled storage, but it requires considerable support from the compiler and leads to periodic pauses in program execution. In order to carry out the mark and collect steps, it must be possible for the run-time system to nd all pointers into the heap from outside, nd all heap pointers held within a given object on the heap, mark an object without destroying information, and nd all heap objects on a linear sweep through the heap. Only the questions of nding pointers aect the compiler; there are three principal possibilities for doing this:
1. The locations of all pointers are known beforehand and coded into the marking algo- rithm.
2. Pointers are discovered by a dynamic type check. (In other words, by examining a storage location we can discover whether or not it contains a pointer.)
3. The compiler creates a template for each activation record and for the type of every object that can appear on the heap. Pointer locations and (if necessary) the object length can be determined from the template.
Pointers in the stack can also be indicated by linking them together into a chain, but this would certainly take too much storage on the heap.
Most LISP systems use a combination of (1) and (2). For (3) we must know the target type of every pointer in order to be able to select the proper template for the object referenced. This could be indicated in the object itself, but storage would be saved if the template carried the number or address of the proper template as well as the location of the pointer. In this manner we also solve the problem of distinguishing a pointer to a record from the pointer to its rst component. Thus the template for an ALGOL 68 structure could have the following structure:
Length of the structure (in storage units)
For each storage unit, a Boolean value `reference'
For each reference, the address of the template of the referenced type.
If dynamic arrays or variants are allowed in records then single Boolean values indicating the presence of pointers are no longer adequate. In the rst case, the size and number of components are no longer known statically. The template must therefore indicate the location of descriptors, so that they can be interpreted by the run-time system. In the second case the position of the variant selector and the dierent interpretations based upon its value must be known. If, as in Pascal, variant records without explicit tag elds are allowed, then garbage collection is no longer possible.
Garbage collection also requires that all internal temporaries and registers that can contain references must be identied. Because this is very dicult in general it is best to arrange the generated code so that, whenever a garbage collection might occur, no references remain in temporaries or registers.
The third recycling strategy requires us to attach a counter to every object in the heap. This counter is incremented whenever a reference to the object is created, and decremented whenever a reference is destroyed. When the counter is decremented to its initial value of 0, storage for the object can be recycled because the object is obviously inaccessible. Mainte- nance of the counters results in higher administrative and storage costs, but the overheads are distributed. The program simply runs slower overall; it does not periodically cease normal operation to reclaim storage. Unfortunately, the reference counter method does not solve all problems:
Reference counts in a cyclic structure will not become 0 even after the structure as a whole becomes inaccessible.
If a counter overows, the number of references to the object is lost.
A complete solution requires that the reference counters be backed up by a garbage col- lector.
To support storage management by reference counting, the compiler must be able to iden- tify all assignments that create or destroy references to heap objects. The code generated for such assignments must include appropriate updating of the reference counts. Diculties arise when variant records may contain references, and assignments to the tag eld identifying the variant are allowed: When such an assignment alters the variant, it destroys the reference even though no direct manipulation of the reference has taken place. Similar hidden destruc- tion occurs when there is a jump out of a procedure that leads to deletion of a number of activation records containing references to heap objects. Creation of references is generally easier to keep track of, the most dicult situation probably being assignment of a composite value containing references as minor components.