📄 memory.txt
字号:
Memory Management Routines
--------------------------
The stdlib memory management routines let you dynamically allocate storage on
the heap. These routines are somewhat similar to those provided by the "C"
programming language. However, these routines do not perform garbage
collection, as this would introduce too many restrictions and have a very
adverse effect on speed.
The following paragraph gives a description of how the memory management
routines work. These routines may be updated in future revisions, however,
so you should never make assumptions about the structure of the memory
management record (described below) or else your code may not work on the
next revision.
The allocation/deallocation routines should be fairly fast. Malloc and free
use a modified first/next fit algorithm which lets the system quickly find a
memory block of the desired size without undue fragmentation problems (average
case). The memory manager data structure has an overhead of eight bytes
(meaning each malloc operation requires at least eight more bytes than you ask
for) and a granularity of 16 bytes. The overhead (eight bytes) per allocated
block may seem rather high, but that is part of the price to pay for faster
malloc and free routines. All pointers are far pointers and each new item is
allocated on a paragraph boundary. The current memory manager routines always
allocate (n+8) bytes, rounding up to the next multiple of 16 if the result is
not evenly divisible by sixteen. The first eight bytes of the structure are
used by the memory management routines, the remaining bytes are available for
use by the caller (malloc, et. al., return a pointer to the first byte beyond
the memory management overhead structure).
NOTE: There was a major change in the way this package works starting with
version 30 of the library. Prior to version 30, MemInit required a parameter
in the DX register to determine where to allocate the heap and how much
storage to allocate. Furthermore, the older versions called DOS to deallocate
memory then reallocate it for the heap. Finally, the older versions required
that you set up a global variable "PSP" containing the program segment
prefix value.
As of version 30, MemInit was split into two routines: MemInit and MemInit2.
MemInit allocates all of available memory (like the standard version of the
earlier MemInit) whereas MemInit2 lets you specify the location and size
of the heap. The new version calls DOS to get the PSP (so you don't need
to declare the PSP variable just for MemInit). The new version does not
reallocate memory blocks with DOS calls (which created some problems,
especially with debugger programs). Finally the new versions work fine
with ".EXE" files which do not get all leftover memory allocated to them.
Most older STDLIB programs will work just fine with the new MemInit routine.
If you relied on MemInit to reallocate memory for you, or if you specified
the location of the heap, you will need to modify your program to use these
new versions of the MemInit routine.
Routine: MemInit
-----------------
Category: Memory Management Routine
Registers on Entry: Nothing
Globals Affected: zzzzzzseg - segment name of the last segment in your
program
Registers on return: CX - number of paragraphs actually reserved by MemInit
Flags affected: None
Example of Usage:
; Don't forget to set up
; zzzzzzseg before calling
; MemInit
MemInit
Description: This routine initializes the memory manager system. You must
call it before using any routines which call any of the memory
manager procedures (since a good number of the stdlib routines
call the memory manager, you should get in the habit of always
calling this routine.) The system will "die a horrible death"
if you call a memory manager routine (like malloc) without first
calling MemInit.
This routine expects you to define (and set up) a global
names: zzzzzzseg. "zzzzzzseg" is a dummy segment which
must be the name of the very last segment defined in your
program. MemInit uses the name of this segment to determine the
address of the last byte in your program. If you do not
declare this segment last, the memory manager will overwrite
anything which follows zzzzzzseg. The "shell.asm" file
provides you with a template for your programs which properly
defines this segment.
On return from MemInit, the CX register contains the number of
paragraphs actually allocated.
Include: stdlib.a or memory.a
Routine: MemInit2
------------------
Category: Memory Management Routine
Registers on Entry: ES- segment address of the start of the heap.
CX- Number of paragraphs to allocate for the heap.
Registers on return: None
Flags affected: None
Example of Usage:
mov cx, seg HeapSeg
mov es, cx
mov cx, HeapSize ;In paragraphs!
MemInit2
Description: This routine initializes the memory manager system. You must
call it before using any routines which call any of the memory
manager procedures (since a good number of the stdlib routines
call the memory manager, you should get in the habit of always
calling this routine.) The system will "die a horrible death"
if you call a memory manager routine (like malloc) without first
calling MemInit2 (or MemInit).
This routine lets you decide where the heap lies in memory
(as opposed to MemInit which uses all available bytes from
the end of your program to the end of memory).
Note: you should only call MemInit or MemInit2 once in your
program.
Include: stdlib.a or memory.a
Routine: Malloc
----------------
Category: Memory Management Routine
Registers on Entry: CX - number of bytes to reserve
Registers on return: CX - number of bytes actually reserved by Malloc
ES:DI - ptr to 1st byte of memory allocated by Malloc
Flags affected: Carry=0 if no error.
Carry=1 if insufficient memory.
Example of Usage:
mov cx, 256
Malloc
jnc GoodMalloc
print db "Insufficient memory to continue.",cr,lf,0
jmp Quit
GoodMalloc: mov es:[di], 0 ;Init string to NULL
Description: Malloc is the workhorse routine you use to allocate a block of
memory. You give it the number of bytes you need and if it
finds a block large enough, it will allocate the requested
amount and return a pointer to that block.
Most memory managers require a small amount of overhead for each
block they allocate. Stdlib's (current) memory manager requires
an overhead of eight bytes. Furthermore, the grainularity is 16
bytes. This means that Malloc always allocates blocks of memory
in paragraph multiples. Therefore, Malloc may actually reserve
more storage than you specify. Therefore, the value returned in
CX may be somewhat greater than the requested value. By setting
the minimum allocation size to a paragraph, however, the
overhead is reduced and the speed of Malloc is improved by a
considerable amount.
Stdlib's memory management does not do any garbage collection.
Doing so would place too many demands on Malloc's users.
Therefore, it is quite possible for you to fragment memory with
multiple calls to maloc, realloc, and free. You could wind up in
a situation where there is enough free memory to satisfy your
request, but there isn't a single contiguous block large enough
for the request. Malloc treats this as an insufficient memory
error and returns with the carry flag set.
If Malloc cannot allocate a block of the requested size, it
returns with the carry flag set. In this situation, the contents
of ES:DI is undefined. Attempting to dereference this pointer
will produce erratic and, perhaps, disasterous results.
Include: stdlib.a or memory.a
Routine: Realloc
-----------------
Category: Memory Management Routine
Registers on Entry: CX - number of bytes to reserve
ES:DI - pointer to block to reallocate.
Registers on return: CX - number of bytes actually reserved by Realloc.
ES:DI - pointer to first byte of memory allocated by
Realloc.
Flags affected: Carry = 0 if no error.
Carry = 1 if insufficient memory.
Example of Usage:
mov cx, 1024 ;Change block size to 1K
les di, CurPtr ;Get address of block into ES:DI
realloc
jc BadRealloc
mov word ptr CurPtr, di
mov word ptr CurPtr+2, es
Description: Realloc lets you change the size of an allocated block in the
heap. It allows you to make the block larger or smaller.
If you make the block smaller, Realloc simply frees (returns
to the heap) any leftover bytes at the end of the block. If
you make the block larger, Realloc goes out and allocates a
block of the requested size, copies the bytes form the old
block to the beginning of the new block (leaving the bytes at
the end of the new block uninitialized)), and then frees the
old block.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -