INF: Patching malloc to Reuse Memory Within an Allocated Block

ID Number: Q47958

5.00 5.10 6.00 6.00a 6.00ax

MS-DOS

Summary:

In Microsoft C versions 5.0, 5.1, 6.0, 6.0a, and 6.0ax, the malloc()

family of functions properly reuse the blocks of memory that they

allocate from MS-DOS. The size of a block that malloc() allocates is 8K

bytes by default, but can be modified by assigning a different block

size in bytes to the C run-time library variable "_amblksiz", as noted

on page 33 of the "Microsoft C Optimizing Compiler: Run-Time

Library Reference" version 5.1 manual.

However, for small suballocations of "chunks" (author's terminology)

within an 8K block, previously freed chunks will not be immediately

reused and fragmentation within blocks can occur; this can cause

MS-DOS programs that make many small (for example, 10-byte)

allocations to prematurely run out of memory. This problem occurs

because the "rover" pointer that points to the next chunk of memory to

be allocated points to the memory after the last chunk allocated

without being set to point to the beginning of chunks that were freed.

Reducing the size of allocated blocks by declaring _amblksiz as above

and assigning values under 8096 to it may help reduce fragmentation

within blocks in some cases simply because there is less memory to

lose to fragmentation per block, and your allocations and frees are

more likely to be on reusable block boundaries.

A better alternative is to allocate large blocks yourself, then

perform your own memory management within them to prevent

fragmentation within blocks.

If you have the C run-time library source code (available through

Microsoft End User Sales and Service), you can force the rover pointer

to point at the bottom of the block prior to a memory request as noted

below, so that any adequately large freed chunks will be reused. This

technique will result in executable speed degradation, but will more

fully allocate the last bytes of memory.

More Information:

To change the behavior of the rover pointer to reallocate freed chunks

of memory within a block, make the following change to line 83 of

AMALLOC.ASM, the workhorse module called by malloc() functions:

1. Delete or comment out line 83 with a semicolon (;), as follows:

; mov si,[bx].roveroff; si = starting rover offset

2. Replace the line above with the following two lines:

mov si,[bx].bottom

mov [bx].roveroff,si ;*** put rover at bottom each time

3. Reassemble AMALLOC.ASM with MASM, as follows

masm /Mx /Dmem_L amalloc;

where the /Mx option preserves symbol name case sensitivity, and

/Dmem_L defines the constant to indicate large memory model for

pointers defined by macros in AMALLOC.ASM and other .ASM files used

for the C library. The constant "mem_L" is for large model, "mem_S"

for small, "mem_C" for compact, and "mem_M" is for medium model.

4. Either link with the new AMALLOC.OBJ (and /NOE), or use lib to

replace the module in the appropriate memory model library, as

follows:

lib llibcer.lib -+amalloc;

Additional reference words: 5.00 5.10 6.00 6.00a 6.00ax