VMALLOC(3)

NAME
vmalloc - virtual memory allocation

SYNOPSIS

  Regions

  Allocation functions

  Debugging

  Profiling

  Information and statistics

  Malloc-compatible functions

DEPRECATION NOTICE
In the 2021 ksh 93u+m distribution, vmalloc(3) was deprecated for being unstable and wasteful in comparison to malloc(3) implementations that come with modern operating systems. By default, the interfaces described here map to the OS's standard malloc(3) implementation. vmalloc can be enabled at compile time by passing -D_AST_vmalloc in CCFLAGS.

DESCRIPTION
These functions for dynamic storage allocation work in regions of memory. Each region has an allocation method for parceling out blocks of storage and a memory discipline for obtaining raw space. Automatic locking prevents interference by reentrant access to a region.

Pointers to space have type void* where void is #defined as void if possible, otherwise char. Space is counted in type size_t.

  Regions
Regions have type Vmalloc_t. Two predefined regions are pointed to by:

A general-purpose region, with best-fit
    allocation, and system memory discipline Vmdcsystem.

These functions manipulate regions:

vmopen creates a region with memory discipline disc, allocation method meth, and a setting for control flags. It returns a pointer to the region on success and NULL on failure. The flags, represented by bit values or-ed together, are:

This region may be accessed concurrently by multiple threads or processes.

Place tracing messages for each allocation event
    on the tracing file established by vmtrace.

VM_DBCHECK, VM_DBABORT
    See Debugging below.

vmclose closes a region and releases all associated memory according to the region's discipline. The first segment obtained from the discipline's memoryf function (see `Disciplines' below) will be the last released. vmclose returns -1 on failure and a non-negative value otherwise.

vmclear frees all allocated blocks in region regardless of methods. It returns -1 on failure and a non-negative value otherwise.

vmcompact releases as much of a region's free space to its discipline's memoryf function as possible. It returns a nonnegative value on success and -1 on failure.

vmset adjusts and queries a region's flags. The indicated flags are turned on if type is nonzero, off if zero. vmset returns the previous value of all flags. Thus, vmset(region,0,0) queries the flags without changing them. In addition to the settable flags, one of VM_MTBEST, VM_MTDEBUG, VM_MTPROFILE, VM_MTPOOL, or VM_MTLAST is returned to indicate the method used in creating the region.

vmdisc changes the discipline of region to the given new discipline disc if disc is not NULL and its memoryf function is the same as the current discipline. If the current discipline has an exceptf function, it will be called with event VM_DISC. This function always returns the current discipline.

vmmopen creates a region to allocate memory obtained via either mmap(2) when project < 0 or shmget(2) when project >= 0. The region is built from a single memory segment guaranteed to be at least as large as size. When project >= 0, file and project are used in a call to ftok(3) to get a key suitable for getting a shared memory segment via shmget(2). Otherwise, file is the backing store for the mapped data. In this case, not only the region may be used concurrently by different processes, it is also persistent. That is, process could even exit, move the file to a different but similar machine then restart and open the same region to continue working.

Note that Vmalloc can protect concurrent accesses only on region entry and exit for memory allocation operations. This means that at the time when regions are being opened or closed, there will be no protection for the memory segments being attached into or detached from process memory space. This limitation has a special impact on vmmopen() as follows.

A shared memory segment opened via vmmopen() corresponds uniquely to a combination of the file and project parameters. Thus, if multiple vmmopen() calls are done in the same process using a same combination of file and project, the joined behavior of such regions will be unpredictable when opening and closing are done concurrently with other memory allocation operations. Beware that this effect can be subtle with library functions that may attempt to create their own memory allocation regions.

vmmvalue manages pairs of key and value in a region opened via vmopen(). If op is VM_MMGET, the value associated with key is returned. If op is VM_MMSET, the value associated with key will be set to value. If op is VM_MMADD, the value associated with key will be treated as a signed long value to which val (also treated as a signed long value) will be added. The call always returns the updated data value associated with key.

vmmcleanup sets region up to remove backing store or shmid on closing.

vmmaddress computes an address suitable for attaching a shared memory segment or memory mapping a segment of file data of the given size. The address is chosen with hope to minimize collision with other activities related to memory such as growth of stack space or space used for dynamically linked libraries, etc.

  Allocation functions
vmalloc returns a pointer to a block of the requested size in a region, aligned to the strictest alignment that is suitable for the needs of any basic data type. It returns NULL on failure.

vmalign works like vmalloc, but returns a block aligned to a common multiple of align and the strictest alignment.

vmresize attempts to change the length of the block pointed to by addr to the specified size. If that is impossible and type has at least one of VM_RSMOVE and VM_RSCOPY, a new block is allocated and the old block is freed. The bit VM_RSCOPY also causes the new block to be initialized with as much of the old contents as will fit. When a resized block gets larger, the new space will be cleared if type has the bit VM_RSZERO. vmresize returns a pointer to the final block, or NULL on failure. If addr is NULL, vmresize behaves like vmalloc; otherwise, if size is 0, it behaves like vmfree.

vmfree makes the currently allocated block pointed to by addr available for future allocations in its region. If addr is NULL, vmfree does nothing. It returns -1 on error, and nonnegative otherwise.

vmnewof is a macro function that attempts to change the length of the block pointed to by addr to the size n*sizeof(type)+x. If the block is moved, new space will be initialized with as much of the old content as will fit. Additional space will be set to zero.

vmoldof is similar to vmnewof but it neither copies data nor clears space.

vmgetmem provides a handy function to create/close regions and allocate/free memory based on chunks of memory obtained from the heap region Vmheap.

This call opens a new region.

This call closes the given region.

This call allocates a block of length n and clears it to zeros.

This call frees the block p.

This call resizes the block p to length n
    and clears the new memory to zeros if the block grows. The block may be moved as deemed necessary by the allocator.

  Memory disciplines
Memory disciplines have type Vmdisc_t, a structure with these members:

If this value is positive, all size arguments to the
    memoryf function will be multiples of it.

Points to a function to get or release segments of space for the
    region.

If this pointer is not NULL,
    the function it points to is called to announce events in a region.

There are two standard disciplines, both with round being 0 and exceptf being NULL.

A discipline whose memoryf function gets space from the operation system
    via different available methods which include mmap(2), sbrk(2) and functions from the WIN32 API. For historical reason, Vmdcsbrk is also available and functions like Vmdcsystem.

A discipline whose memoryf function gets space from the region Vmheap.
    A region with Vmdcheap discipline and Vmlast allocation is good for building throwaway data structures.

A memoryf function returns a pointer to a memory segment on success, and NULL on failure. When nsz >= 0 and csz > 0, the function first attempts to change the current segment addr to fit nsz (for example, nsz == 0 means deleting the segment addr). If this attempt is successful, it should return addr. Otherwise, if nsz > csz, the function may try to allocate a new segment of size nsz-csz. If successful, it should return the address of the new segment. In all other cases, it should return NULL.

An exceptf function is called for events identified by type, which is coded thus:

This event is raised at the start of the process to open a new region.
    Argument obj will be a pointer to an object of type void* initialized to NULL before the call. The return value of exceptf is significant as follows: On a negative return value, vmopen will terminate with failure. On a zero return value, exceptf may set *((void**)obj) to some non-NULL value to tell vmopen to allocate the region handle itself via memoryf. Otherwise, the region handle will be allocated from the Vmheap region. On a positive return value, the new region is being reconstructed based on existing states of some previous region. In this case, exceptf should set *(void**)obj to point to the field Vmalloc_t.data of the corresponding previous region (see VM_CLOSE below). If the handle of the previous region was allocated via memoryf as discussed above in the case of the zero return value, then it will be exactly restored. Otherwise, a new handle will be allocated from Vmheap. The ability to create regions sharing the same states allows for managing shared and/or persistent memory.

This event is raised at the end of the process to open a new region.
    The return value of exceptf will be ignored.

This event is raised at the start of the process to close a region,
    The return value of exceptf is significant as follows: On a negative return value, vmclose immediately returns with failure. On a zero return value, vmclose proceeds normally by calling memoryf to free all allocated memory segments and also freeing the region itself. On a positive return value, vmclose will only free the region without deallocating the associated memory segments. That is, the field Vmalloc_t.data of the region handle remains intact. This is useful for managing shared and/or persistent memory (see VM_OPEN above).

This event is raised at the end of the process to close a region.
    The return value of exceptf will be ignored.

An attempt to extend the region by the amount
    (size_t)obj failed. The region is unlocked, so the exceptf function may free blocks. If the function returns a positive value the memory request will be repeated.

The discipline structure is being changed.

  Allocation methods
Methods are of type Vmethod_t*.

An approximately best-fit allocation strategy.

A strategy for building structures that are only deleted in whole.
    Only the latest allocated block can be freed. This means that as soon as a block a is allocated, vmfree calls on blocks other than

A strategy for blocks of one size,
    set by the first vmalloc call after vmopen or vmclear.

An allocation strategy with extra-stringent checking and locking.
    It is useful for finding misuses of dynamically allocated memory, such as writing beyond the boundary of a block, or freeing a block twice.

An allocation method that records and prints summaries of memory usage.

  Debugging
The method Vmdebug is used to debug common memory violation problems. When a problem is found, a warning message is written to file descriptor 2 (standard error). In addition, if flag VM_DBABORT is on, the program is terminated by calling abort(2). Each message is a line of self-explanatory fields separated by colons. The optional flag -DVMFL, if used during compilation, enables recording of file names and line numbers. The following functions work with method Vmdebug.

vmdebug resets the file descriptor to write out warnings to the given argument. By default, this file descriptor is 2, the standard error. vmdebug returns the previous file descriptor.

vmdbcheck checks a region using Vmdebug or Vmbest for integrity. If Vmdebug, this also checks for block overwriting errors. On errors, vmdbwarn is called. If flag VM_DBCHECK is on, vmdbcheck is called at each invocation of vmalloc, vmfree, or vmresize.

vmdbwatch causes address addr to be watched, and reported whenever met in vmalloc, vmresize or vmfree. The watch list has finite size and if it becomes full, watches will be removed in a first-in-first-out fashion. If addr is NULL, all current watches are canceled. vmdbwatch returns the watch bumped out due to an insertion into a full list or NULL otherwise.

vmdbwarn is an internal function that processes warning messages for discovered errors. It can't be called from outside the vmalloc package, but is a good place to plant debugger traps because control goes there at every trouble.

  Profiling
The method Vmprofile is used to profile memory usage. Profiling data are maintained in private memory of a process so Vmprofile should be avoided from regions manipulating persistent or shared memory. The optional flag -DVMFL, if used during compilation, enables recording of file names and line numbers.

vmprofile prints memory usage summary. The summary is restricted to region vm if vm is not NULL; otherwise, it is for all regions created with Vmprofile. Summary records are written to file descriptor fd as lines with colon-separated fields. Here are some of the fields:

n_alloc,n_free:
    Number of allocation and free calls respectively. Note that a resize operation is coded as a free and an allocation.

s_alloc,s_free:
    Total amounts allocated and freed. The difference between these numbers is the amount of space not yet freed.

max_busy, extent:
    These fields are only with the summary record for region. They show the maximum busy space at any time and the extent of the region.

  Information and statistics
vmbusy returns the busy status of a region. A region is busy if some allocation operation is accessing it.

vmregion returns the region to which the block pointed to by addr belongs. This works only in regions that allocate with Vmbest, Vmdebug or Vmprofile.

vmsegment finds if some segment of memory in region contains the address addr. It returns the address of a found segment or NULL if none found.

vmwalk walks all segments in region or if region is NULL, all segments in all regions. At each segment, (*walkf)(vm,addr,size,disc) is called where vm is the region, addr is the segment, size is the size of the segment, and disc is the region's discipline. If walkf returns a negative value, the walk stops and returns the same value. On success, vmwalk returns 0; otherwise, it returns -1.

vmaddr checks whether addr points to an address within some allocated block of the given region. If not, it returns -1. If so, it returns the offset from the beginning of the block. The function does not work for a Vmlast region except on the latest allocated block.

vmsize returns the size of the allocated block pointed to by addr. It returns -1 if addr does not point to a valid block in the region. Sizes may be padded beyond that requested; in particular no block has size 0. The function does not work for a Vmlast region except on the latest allocated block.

vmstat gathers statistics on the given region. If region is NULL, it computes statistics for the Malloc calls. This may include summing statistics from more than one regions constructed to avoid blocking due to parallel or asynchronous operations. If statb is not NULL, vmstat computes and stores the statistics in statb then returns 0. If statb is NULL, no statistics will be computed and the returned value is either 1 if the region is busy, i.e., being accessed by some allocation call or 0 otherwise. A Vmstat_t structure has at least these members:

Bookkeeping overhead is counted in extent, but not in s_busy or s_free.

vmtrace establishes file descriptor fd as the trace file and returns the previous value of the trace file descriptor. The trace descriptor is initially invalid. Output is sent to the trace file by successful allocation events when flag VM_TRACE is on.

Tools for analyzing traces are described in mtreplay(1). The trace record for an allocation event is a line with colon-separated fields, four numbers and one string.

old Zero for a fresh allocation; the address argument for freeing and resizing.

new Zero for freeing; the address returned by allocation or resizing.

size
    The size argument for allocation or resizing; the size freed by freeing. Sizes may differ due to padding for alignment.

region
    The address of the affected region.

method
    A string that tells the region's method: best, last, pool, profile, or debug.

vmtrbusy outputs a trace of all currently busy blocks in region vm. This only works with the Vmbest, Vmdebug and Vmprofile methods.

vmdata returns the core data of the given region. The core data hold the data structures for allocated and free blocks. Depending on the region discipline, the core data of a region may be in shared or persistent memory even if the region pointer created with vmopen is always in private process memory.

  Malloc-compatible functions
This set of functions implement malloc(3). They allocate via the Vmregion region which is initially set to be Vmheap. Concurrent accesses are supported unless an application change Vmregion to something other than Vmheap. New regions may be created on the fly to avoid blocking. The maximum number of regions that can be created this way is set to 64 by default. An application could reduce this number by calling setregmax(regmax) to set the maximum number of these extra regions to regmax. setregmax() always returns the previous value.

These functions are instrumented for run-time debugging, profiling and tracing. For accurate reporting of files and line numbers, application code should include vmalloc.h and compile with -DVMFL. The VMALLOC_OPTIONS environment variable, checked once before the first memory allocation, controls the memory allocation method, debugging and tracing; its value is a comma or space separated list of [no]name[=value] options. The options are:

abort
    If Vmregion==Vmdebug then VM_DBABORT is set, otherwise _BLD_DEBUG enabled assertions abort() on failure.

break
    Try sbrk() block allocator first.

check
    If Vmregion==Vmbest then the region is checked every op.

free
    Disable addfreelist().

keep
    Disable free -- if code works with this enabled then it probably accesses freed data.

method=method
    Sets Vmregion=method if not defined, method (Vm prefix optional) may be one of { best debug last profile }.

mmap
    Try mmap() block allocator first if break is not set.

period=n
    Sets Vmregion=Vmdebug if not defined, if Vmregion==Vmdebug the region is checked every n ops.

profile=file
    Sets Vmregion=Vmprofile if not set, if Vmregion==Vmprofile then profile info printed to file file.

start=n
    Sets Vmregion=Vmdebug if not defined, if Vmregion==Vmdebug region checking starts after n ops.

trace=file
    Enables tracing to file file.

warn=file
    Sets Vmregion=Vmdebug if not defined, if Vmregion==Vmdebug then warnings printed to file file.

watch=address
    Sets Vmregion=Vmdebug if not defined, if Vmregion==Vmdebug then address is watched.

Output files are created if they don't exist. &n and /dev/fd/n name the file descriptor n which must be open for writing. The pattern %p in a file name is replaced by the process ID.

VMALLOC_OPTIONS combines the features of these obsolete environment variables: { VMCHECK VMDEBUG VMETHOD VMPROFILE VMTRACE }.

RECENT CHANGES
Vmlast: allocated blocks are now allowed to be resized (09/1998).

SEE ALSO
mtreplay(1), malloc(3).

AUTHOR
Kiem-Phong Vo, kpv@research.att.com