You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
11 KiB
300 lines
11 KiB
\chapter{MEMORY MANAGER}
|
|
The purpose of the memory manager utilities is to allow an applications
|
|
programmer to write standard, readable FORTRAN-77 code while employing
|
|
dynamic memory management for REAL, INTEGER, and LOGICAL type arrays.
|
|
|
|
Because the array sizes in most programs are problem dependent, the
|
|
program's memory requirements are not known until the program is running.
|
|
Since FORTRAN-77 does not provide for dynamic memory allocation, the
|
|
programmer has to either predict the maximum memory requirement or use
|
|
machine dependent requests for memory. In addition, dynamic memory
|
|
allocation is an error prone exercise which tends to make the source code
|
|
difficult to read and maintain.
|
|
|
|
The memory manager utilities are written in standard FORTRAN-77 and provide
|
|
an interface which encourages readable coding and efficient use of memory
|
|
resources. Machine dependencies are isolated through the use of the FORTRAN
|
|
extension library (Chapter~\ref{sec:extlib}). All memory requests are in
|
|
terms of {\em numeric storage units} (the amount of memory occupied by an
|
|
integer, real, or logical datum~\cite{ansi}).
|
|
|
|
The memory manager utility is divided into three categories; basic routines,
|
|
advanced routines, and development aids. These categories will be discussed
|
|
in sections \ref{sec:mbas} through \ref{sec:mdev}.
|
|
|
|
|
|
\section{Pointer System}
|
|
In order to use the memory manager properly, the user must first understand
|
|
the concept of a base array with pointers for accessing memory locations.
|
|
The memory manager references all memory relative to a user supplied base
|
|
array. A reference to memory is made in terms of an index or pointer to
|
|
this base array. The pointers which the memory manager provides may take on
|
|
a wide range of values, including negative numbers.
|
|
|
|
The base array must comply with the following rules:
|
|
\begin{enumerate}
|
|
\item The array must be of type INTEGER, REAL, or LOGICAL. Modified word
|
|
length storage arrays such as INTEGER\last2 or REAL\last8 will result in
|
|
invalid pointers with no error message.
|
|
|
|
\item The lower bound of the array subscript must be one.
|
|
\end{enumerate}
|
|
|
|
The following FORTRAN statement defines a valid base array:
|
|
|
|
DIMENSION A(1)
|
|
|
|
ONLY ONE BASE ARRAY MAY BE USED IN A PROGRAM.
|
|
|
|
In order to use memory allocated by the memory manager, the user merely
|
|
needs to pass the base array with the correct pointer to a subprogram. For
|
|
example, for a base array A and a pointer IP, a subroutine call would be:
|
|
|
|
\verb+CALL SUBBIE ( A(IP) )+
|
|
|
|
Although the programmer is not restricted to using the allocated memory in
|
|
subprograms only, the recommended usage for the memory manager is to
|
|
allocate dynamic arrays in the main program and then pass them to
|
|
subroutines.
|
|
|
|
|
|
\section{Basic Routines}\label{sec:mbas}
|
|
The basic memory manager routines are those which are most commonly used and
|
|
require little understanding of the internal workings of the utility.
|
|
|
|
\subsection{Initialize (MDINIT)}
|
|
The memory manager {\em must} be initialized with a call to MDINIT before
|
|
any memory can be allocated. The main purpose of the initialization is to
|
|
determine the location of the base array in memory.
|
|
|
|
\verb+CALL MDINIT (BASE)+
|
|
|
|
\begin{argy}{BASE}{INTEGER, LOGICAL or REAL Array}{Read Only}
|
|
This array is used as a base reference to all dynamically allocated memory.
|
|
\end{argy}
|
|
|
|
\subsection{Define Dynamic Array (MDRSRV)}
|
|
MDRSRV declares a new dynamic array. The user supplies the space required,
|
|
and a pointer to the new space is returned. Note that the contents of the
|
|
new storage are undefined.
|
|
|
|
\verb+CALL MDRSRV (NAME, NEWPNT, NEWLEN)+
|
|
|
|
\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
|
|
This is the name of the new dynamic array. The memory manager will add this
|
|
name to its internal dictionary; each array must have a unique name. The
|
|
first eight characters are used for comparison, and leading and embedded
|
|
blanks are significant.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NEWPNT}{INTEGER}{Write Only}
|
|
This is the pointer to storage allocated to this dynamic array relative to
|
|
the base array.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NEWLEN}{INTEGER}{Read Only}
|
|
This is the length to be reserved for the new array. Any nonnegative number
|
|
is acceptable. A zero length does not cause any storage to be allocated and
|
|
returns a pointer equal to one.
|
|
\end{argy}
|
|
|
|
\subsection{Delete Dynamic Array (MDDEL)}
|
|
MDDEL releases the memory that is allocated to a dynamic array.
|
|
|
|
\verb+CALL MDDEL (NAME)+
|
|
|
|
\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
|
|
This is the name of the dynamic array which is to be deleted. The array
|
|
name must match an existing name in the dictionary. The first eight
|
|
characters are used for comparison, and leading and embedded blanks are
|
|
significant.
|
|
\end{argy}
|
|
|
|
\subsection{Reserve Memory Block (MDGET)}
|
|
MDGET reserves a contiguous block of memory without associating the block of
|
|
memory with an array. MDGET should be called prior to a series of calls to
|
|
MDRSRV to improve efficiency and to reduce memory fragmentation. Further
|
|
discussion of the operation of MDGET is found in section~\ref{sec:table}.
|
|
|
|
\verb+CALL MDGET (MNGET)+
|
|
|
|
\begin{argy}{MNGET}{INTEGER}{Read only}
|
|
This specifies the desired contiguous block size.
|
|
\end{argy}
|
|
|
|
\subsection{Release Unallocated Memory (MDGIVE)}
|
|
MDGIVE causes the memory manager to return unused storage to the operating
|
|
system, if possible.
|
|
|
|
\verb+CALL MDGIVE ()+
|
|
|
|
|
|
\subsection{Obtain Statistics (MDSTAT)}
|
|
MDSTAT returns memory manager statistics. MDSTAT provides the only method
|
|
for error checking, and thus should be used after other calls to the memory
|
|
manager to assure no errors have occurred.
|
|
|
|
\verb+CALL MDSTAT (MNERRS, MNUSED)+
|
|
|
|
\begin{argy}{MNERRS}{INTEGER}{Write Only}
|
|
This is the total number of errors detected by the memory manager during the
|
|
current execution.
|
|
\end{argy}
|
|
|
|
\begin{argy}{MNUSED}{INTEGER}{Write Only}
|
|
This is the total number of words that are currently allocated to dynamic
|
|
arrays.
|
|
\end{argy}
|
|
|
|
\subsection{Print Error Summary (MDEROR)}
|
|
MDEROR prints a summary of all errors detected by the memory manager. The
|
|
return status of the last memory manager routine called is also printed.
|
|
MDEROR should be called any time an error is detected by a call to MDSTAT.
|
|
|
|
\verb+CALL MDEROR (IUNIT)+
|
|
|
|
\begin{argy}{IUNIT}{INTEGER}{Read Only}
|
|
This is the unit number of the output device.
|
|
\end{argy}
|
|
|
|
\begin{center}
|
|
\begin{tabular}{|rl|} \hline \hline
|
|
\multicolumn{2}{|c|}{ERROR CODES}\\ \hline
|
|
1 & SUCCESSFUL COMPLETION\\
|
|
2 & UNABLE TO GET REQUESTED STORAGE FROM SYSTEM\\
|
|
3 & DATA MANAGER NOT INITIALIZED\\
|
|
4 & DATA MANAGER WAS PREVIOUSLY INITIALIZED\\
|
|
5 & NAME NOT FOUND IN DICTIONARY\\
|
|
6 & NAME ALREADY EXISTS IN DICTIONARY\\
|
|
7 & ILLEGAL LENGTH REQUEST\\
|
|
8 & UNKNOWN DATA TYPE\\
|
|
9 & DICTIONARY IS FULL\\
|
|
10 & VOID TABLE IS FULL\\
|
|
11 & MEMORY BLOCK TABLE IS FULL\\
|
|
12 & OVERLAPPING VOIDS - INTERNAL ERROR\\
|
|
13 & OVERLAPPING MEMORY BLOCKS - INTERNAL ERROR\\
|
|
14 & INVALID MEMORY BLOCK - EXTENSION LIBRARY ERROR \\ \hline \hline
|
|
\end{tabular}
|
|
\end{center}
|
|
|
|
\subsection{Basic Example}
|
|
\begin{verbatim}
|
|
DIMENSION BASE(1)
|
|
CALL MDINIT (BASE)
|
|
CALL MDGET (30)
|
|
CALL MDRSRV ('FIRST', I1, 10)
|
|
CALL MDRSRV ('SECOND', I2, 10)
|
|
CALL MDRSRV (' THIRD', I3, 10)
|
|
CALL MDSTAT (MNERRS, MNUSED)
|
|
IF (MNERRS .NE. 0) THEN
|
|
CALL MDEROR (6)
|
|
STOP
|
|
END IF
|
|
CALL MDDEL (' THIRD')
|
|
CALL MDGIVE ()
|
|
\end{verbatim}
|
|
|
|
\section{Advanced Routines}
|
|
The advanced routines are supplied to give added capability to the user who
|
|
is interested in more sophisticated manipulation of memory. These routines
|
|
are never necessary, but may be very desirable.
|
|
|
|
\subsection{Rename Dynamic Array (MDNAME)}
|
|
MDNAME renames a dynamic array from NAME1 to NAME2. The location of the
|
|
array is not changed, nor is its length.
|
|
|
|
\verb+CALL MDNAME (NAME1, NAME2)+
|
|
|
|
\begin{argy}{NAME1}{CHARACTER\last(\last)}{Read Only}
|
|
This is the old name of the array. The first eight characters are used for
|
|
comparison.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NAME2}{CHARACTER\last(\last)}{Read Only}
|
|
This is the new name of the array. The first eight characters are used.
|
|
\end{argy}
|
|
|
|
\subsection{Adjust Dynamic Array Length (MDLONG)}
|
|
MDLONG changes the length of a dynamic array. The memory manager will
|
|
relocate the array and move its data if storage cannot be extended at the
|
|
array's current location. The user should assume that MDLONG invalidates
|
|
the previous pointer to this array if the array is extended.
|
|
|
|
\verb+CALL MDLONG (NAME, NEWPNT, NEWLEN)+
|
|
|
|
\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
|
|
This is the name of the dynamic array which the user wishes to extend or
|
|
shorten.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NEWPNT}{INTEGER}{Write Only}
|
|
This is the new pointer to the dynamic array.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NEWLEN}{INTEGER}{Read Only}
|
|
This is the new length for the dynamic array.
|
|
\end{argy}
|
|
|
|
\subsection{Locate Dynamic Array (MDFIND)}
|
|
MDFIND returns the pointer and length of storage allocated to a dynamic
|
|
array. This routine would be used if the pointer from an earlier call to
|
|
MDRSRV was not passed to a different subprogram.
|
|
|
|
\verb+CALL MDFIND (NAME, NEWPNT, NEWLEN)+
|
|
|
|
\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
|
|
This is the name of the dynamic array to be located.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NEWPNT}{INTEGER}{Write Only}
|
|
This is the pointer to the dynamic array relative to the user's reference
|
|
array.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NEWLEN}{INTEGER}{Write Only}
|
|
This is the length of the dynamic array.
|
|
\end{argy}
|
|
|
|
\subsection{Compress Storage (MDCOMP)}
|
|
MDCOMP causes fragmented memory to be consolidated. Note that this may
|
|
cause array storage locations to change. It is important to realize that
|
|
all pointers must be recalculated by calling MDFIND after a compress
|
|
operation. A call to MDCOMP prior to MDGIVE will result in the return of
|
|
the maximum memory to the system.
|
|
|
|
\verb+CALL MDCOMP ()+
|
|
|
|
|
|
\section{Development Aids}\label{sec:mdev}
|
|
The routines in this section are designed to aid the programmer during
|
|
development of a program, and probably would not be used during execution of
|
|
a mature program.
|
|
|
|
\subsection{List Storage Tables (MDLIST)}
|
|
MDLIST prints the contents of the memory manager's internal tables.
|
|
Section~\ref{sec:table} describes these tables.
|
|
|
|
\verb+CALL MDLIST (IUNIT)+
|
|
|
|
\begin{argy}{IUNIT}{INTEGER}{Read Only}
|
|
This is the unit number of the output device.
|
|
\end{argy}
|
|
|
|
\subsection{Print Dynamic Array (MDPRNT)}
|
|
MDPRNT prints the contents of an individual array.
|
|
|
|
\verb+CALL MDPRNT (NAME, IUNIT, NTYPE)+
|
|
|
|
\begin{argy}{NAME}{CHARACTER\last(\last)}{Read Only}
|
|
This is the name of the array to be printed.
|
|
\end{argy}
|
|
|
|
\begin{argy}{IUNIT}{INTEGER}{Read Only}
|
|
This is the unit number of the output device.
|
|
\end{argy}
|
|
|
|
\begin{argy}{NTYPE}{CHARACTER\last(\last)}{Read Only}
|
|
NTYPE indicates the data type of the data to be printed; "R" for REAL, or
|
|
"I" for INTEGER. Note that this is not necessarily the declared type of the
|
|
base array.
|
|
\end{argy}
|
|
|