0% found this document useful (0 votes)
83 views62 pages

4 Memory Management

This document summarizes different mechanisms for memory allocation in programming languages: Static allocation assigns memory at compile time for variables like global variables and constants. Dynamic allocation uses stacks and heaps. Stacks allocate memory for function calls and blocks in LIFO order using activation records. Heaps allocate variable-sized blocks and allow deallocation at any time, requiring management of free blocks. Static scoping determines variable access through static nesting and a static link or display from each activation record.

Uploaded by

Abra
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
83 views62 pages

4 Memory Management

This document summarizes different mechanisms for memory allocation in programming languages: Static allocation assigns memory at compile time for variables like global variables and constants. Dynamic allocation uses stacks and heaps. Stacks allocate memory for function calls and blocks in LIFO order using activation records. Heaps allocate variable-sized blocks and allow deallocation at any time, requiring management of free blocks. Static scoping determines variable access through static nesting and a static link or display from each activation record.

Uploaded by

Abra
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 62

Memory Management

Memory allocation

• Three mechanisms for memory allocation


◦ Static. Memory allocated at compile time
◦ Dynamic. Memory allocated at execution time
• Stack: Objects allocated LIFO
• Heap: Objects can be allocated and deallocated at any time
Static allocation

• An object has an absolute address that is maintained throughout the


execution of a program
• The following are usually statically allocated
◦ Global variables
◦ Local variables of subprograms, in the absence of recursion
◦ Constants determined at run time
◦ Tables used during run time (for type checking, garbage collection
etc.)
Static allocation for subprograms
Static allocation does not permit recursion

• We illustrate the problem with an illegal program (FORTRAN doesn’t


allow recursion)

SUBROUTINE ERROR(N)
IF (N.LE.1) RETURN
CALL ERROR(n-1)
END

CALL ERROR (3)

• Assume this is legal


• There is then a unique static area of memory for storing N
◦ First iteration: Store 3
◦ Second iteration: Store 2
◦ The original value is now lost. . .
Dynamic allocation: Stack

• For every runtime instance of a subprogram, we have an activation


record (or frame), that contains the information about this instance
• In a similar (but simpler) way, each block also has an activation record
• The stack (LIFO) is the natural data structure for this
• While not neccessary, a stack can also be used in languages without
recursion, to reduce memory usage
Activation record for anonymous blocks

• This record consists of three parts


◦ Pointers for dynamic chain
◦ Local variables
◦ Intermediate results
Dynamic allocation with a stack

• Implementation with a stack uses


◦ Sequence of calls
◦ Prologue
◦ Epilogue
◦ Return sequence
• The address of the activation record is not known at compile time
• The pointer of the activation record points to the activation record of
the active block
• The information in the activation record is accessible via its offset
◦ The address is the activation record address plus the offset
◦ The offset is determined statically
◦ The sum is computed with a single machine instruction (load or
store)
Activation record for in-line blocks

• Dynamic link (or control link): Pointer to previous record on the stack
• On entry to block: Push
◦ Dynamic link to new record created
◦ Activation record set to pointer to new record
• On exit from block: Pop
◦ Eliminate pointer to current activation record
◦ Set pointer to the activation record on top of stack
Example

{int x=0;
int y=x+1;
{
int z=(x+y)*(x-y);
};
};

• Start: Push record with space for x and y


• Set values for x and y
• Internal block:
◦ Push record for internal block
◦ Set value for z
◦ Pop record for internal block
• Pop record for external block
• Note that in the internal block, x and y cannot be accessed via the
offset, and we need to follow a chain of pointers
Example
In practice

• In many languages, anonymous blocks can be implemented without a


stack
• The compiler can analyze all the nested blocks
◦ Space can be allocated for all variables
◦ This may waste some memory
◦ But no loss of efficiency due to stack management
Activation records for procedures
Management of the stack
Example

{int fact (int n) {


if (n<=1) return 1;
else return n*fact(n-1);
}}
Example

• Parameters: Corresponding to the value of n in the sequence of calls


• Address for result: Address of the location where the final value of
fact(n) should be placed (in the activation record of the call)
• Intermediate results: Space for storing the value of fact(n-1)
• Local variables (not present in this example)
Example: Recursive call of fact(3)
In more detail

{int fact (int n) {


if (n<=1) return 1;
else return n*fact(n-1);
}}
Dynamic allocation with a heap

• Heap: Region of memory in which blocks (and subblocks) can be


allocated and deallocated at arbitrary moments
• This is necessary when the language allows:
◦ Explicit allocation of memory at runtime
◦ Objects of varying size
◦ Objects whose lifetime is not LIFO
• Heap management is nontrivial
◦ Efficient allocation of space: Avoiding fragmentation
◦ Speed of access
Heap: Blocks of fixed size

• The heap is divided into blocks of fixed size


• At the start: All of these blocks are linked in a free list

Each one has a link to the


Points to the first free next free one
one
Heap: Blocks of fixed size

• Allocation of one or more contiguous blocks


• Deallocation: Restore these blocks to the free list
Heap: Blocks of variable size

• Heap initially contains a single block


• Allocation: Find a free block of the appropriate size
• Deallocation: Restore the block to the free list
Problems

• The operations must be efficient


• Avoid wasting memory
◦ Internal fragmentation
◦ External fragmentation
Internal fragmentation

• The space allocated is of size X


◦ A block of size Y > X is allocated
◦ Space of size Y − X is wasted
External fragmentation

• The needed space is available but not usable, as it is broken up into


pieces that are too small
Management of the free list: Single list

• At the start: A single block, whose size is the size of the heap
• At each allocation request: Find a block of the appropriate size
◦ First fit: First block that is large enough
◦ Best fit: Find the smallest block that is large enough
• If the chosen block is much larger than needed, it is divided into two
pieces, and the unused one is added to the free list
Heap management

• Best fit or first fit?


◦ First fit: Faster, worse use of memory
◦ Best fit: Slower, better use of memory
Heap management

• With a single list: Allocation is linear in the number of free blocks


• Better: Use multiple lists. The division of blocks beween the lists can
be
◦ Static
◦ Dynamic. Two examples:
• Buddy system. k lists, with the kth list having blocks of size
2k
◦ If size 2k requested, but not available, allocate a block of
size 2k+1 divided into 2
◦ If a block of size 2k is deallocated, unite it with its other
half, if this is available
• Fibonacci: Similar, but uses Fibonacci numbers
Implementation of scoping rules

• Static scope
◦ Static chain
◦ Display
• Dynamic scope
◦ A-list
◦ Central table of the environment
Static scoping: How to determine the correct association

{ int x=10;
void foo(){
x++;
}
void fie() {
int x=0;
foo();
}

fie();
}

• foo always accesses the same variable x


• x is stored in a certain access record (here main)
• The access record for foo is at the top of the stack
First case

• foo called inside fie


Second case

• foo called by main()

• In both cases
◦ Determine first the activation record where x is located
◦ Access x via the offset from this activation record
Activation record for static scoping
Activation record for static scoping

• Dynamic link (already seen)


• Static link
◦ Pointer to the activation record of the block that immediately
contains the text of the current block
• Note
◦ A dynamic link depends on the execution sequence of the program
◦ A static link depends on the static nesting of the declarations of
the procedure
Static chain: Example

• Sequence of runtime calls: A, B, C, D, E, C


Static chain: Example

• If a subprogram is at level k of nesting, the chain has length k


Example

{ int x;
void A() { x=x+1; }
void B() { int x;
void C() (int y){
int x;
x=y+2;
A();
}
x=0; A(); C(3);
}
x=10;
B();
}
Runtime support

• How is the static link of the call determined?


• The caller should determine the static link
• The caller has the following information
◦ Static nesting of blocks, determined by the compiler
◦ Its own activation record
Runtime support
Determining the pointer

• The caller Ch knows the block nesting


◦ When Ch calls P , it knows that the definition of P is
• Immediately included inCh (k = 0)
• In a block k steps from Ch
• No other case is possible
Determining the pointer

• In this example
◦ Calls A, B, C, D, E, C
◦ Static chain A; (B, 0); (C, 1); (D, 0); (E, 1); (C, 2)
• If k = 0, Ch passes its own SP to P
• If k > 0, we find the pointer after k steps in the static chain
Reducing the costs: The display

• We can reduce the costs from scanning the chain to a constant using
the display
• The static chain is represented by an array, called the display
◦ The ith element of the display is a pointer to the activation record
of the subprogram at nesting level i
◦ If the subprogram is at nested level i, then an object in the external
scope at level h, can be found in the display at level j = i − h
Display

• In the following diagram, Display[i] is the pointer to the activation


record of level i
• The sequence of calls is A, B, C, D, E, C
Display
Display

• Display[i] is the pointer to the activation record of the procedure at


level i
• In this example, the sequence of calls is A, B, C, D, E, C
Display

• If the current procedure is at nesting level i, then the nesting scope at


level h is in Display[i − h]
• If Display is in main memory, an object can be found with two memory
accesses
Management of the Display

• Procedure call manages the display


◦ When Ch calls P at nesting level j, P saves the value of its own
Display[j] in its own activation record, and sets the pointer to
point to a copy of its new activation record pointer
• Modern implementations rarely use this technique, as static chains
longer than 3 are rare
Dynamic scoping

• Under dynamic scoping, the association between names and denotable


objects depends on
◦ The flow of control at runtime
◦ The order in which subprograms are called
• The basic rule is simple:
◦ The current association for a name is that determined by the last
association to have been called and not yet destroyed
Implementation is simple

• Store the names in the activation record


• Search for names via the stack (note: the names themselves may be
long)
• Example: Calls are A, B, C, D
Implementation

• Nonactive associations are in grey


Alternative: A-list

• The associations are stored in an appropriate structure, managed as a


stack
• The same example
A-list

• Simple to implement
• Memory use: Names are listed explicitly
• Management costs:
◦ Entrance/exit from a block: Insertion/removal from a stack
• Access cost: Linear in the depth of the A-list
• The average access cost can be reduced, but at the cost of increasing
the work on entrance/exit from a block
Central table of references (CRT)

• Avoids the costly scanning of A-lists


• The table stores all the distinct names of the program
◦ Static: Access in constant time
◦ Otherwise, use hash functions
• Each name has an association list
◦ Most recent first
◦ Followed by the inactive ones
• Constant access time
Example

• Sequence of calls: A, B, C, D
Analysis of CRT

• More complex than A-list


• Less memory use
◦ If names are used statically, the names themselves are not needed
◦ In any case, each name is stored only once
• Costs of management
◦ Entry/exits from a block: Management of all of the lists of all the
names present in the block
• Access time: Constant (2 indirect accesses)
Exercises
Exercise 1
Using some pseudo-language, write a fragment of code such that the max-
imum number of activation records present on the stack at runtime is not
statically determinable
Exercise 2
In some pseudo-language, write a recursive function such that the maximum
number of activation records present at runtime on the stack is statically
determinable. Can this example be generalised?
Exercise 3
Consider the following code fragment:

A:{int X= 1;
...
B:{X =3;
....
}
....
}

Assume that B is nested one level deeper that A. To resolve the reference to
X present in B, why is it not enough to consider the activation record which
immediately precedes that of B on the stack? Provide a counter-example
filling the spaces in the fragment with dots with appropriate code
Exercise 4
Consider the following program fragment written in a pseudo-language using
static scoping.

void P1 {
void P2 { body-of-P2
} void P3 {
void P4 { body-of-P4 }
body-of-P3 }
body-of-P1
}

Draw the activation record stack region that occurs between the static and
dynamic chain pointers when the following sequence of calls, P 1, P 2, P 3,
P 4, P 2 has been made (is it understood that at this time they are all active:
none has returned).
Exercise 5

Given the following code fragment in a pseudo-language with static scope


and labelled nested blocks (indicated by A: { ... })

A: { int x = 5; goto C;
B: {int x = 4; goto E;
}
C: {int x = 3;
D: {int x = 2;
}
goto B;
E: {int x = 1; // (**)
}
}
}

The static chain is handled using a display. Draw a diagram showing the
display and the stack when execution reaches the point indicated with the
comment (**). As far as the activation record is concerned, indicate what
is the only piece of information required for display handling
Exercise 6
Is it easier to implement the static scope rule or the one for dynamic scope?
Give your reasons.

You might also like