Memory Allocation

Name

malloc, calloc, realloc, free, mallinfo, operator new, operator new[], operator delete, operator delete[] -- Access the System Heap

Synopsis

#include <stdlib.h>
#include <new>
        

void* malloc(size_t size);

void* calloc(size_t nmemb, size_t size);

void* realloc(void* ptr, size_t size);

void free(void* ptr);

struct mallinfo mallinfo(void);

void* operator new(size_t size);

void* operator new[](size_t size);

void* operator new(size_t size, const std::nothrow_t&);

void* operator new(nothrow)[](size_t size, const std::nothrow_t&);

void operator delete(void* ptr);

void operator delete[](void* ptr);

void operator delete(void* ptr, const std::nothrow_t&);

void operator delete[](void* ptr, const std::nothrow_t&);

Description

The dynamic memory allocation package CYGPKG_MEMALLOC provides support for the ISO standard C functions malloc, calloc, realloc and free. Optionally it can provide the C++ new and delete operators. There is extensive support for debugging various problems associated with dynamic memory allocation.

Some of the available target RAM will be needed for application code and static data. If the target uses RedBoot or another ROM monitor for bootstrap then that may also reserve some of the available RAM. On most targets the system heap occupies all remaining RAM, and this is used to satisfy the memory allocation requests. By default the Doug Lea memory allocator (dlmalloc) code is used to manage the heap. This provides a good trade off between efficient use of the memory, fast operation, and resistance to fragmentation. If the eCos configuration includes the kernel then by default the various memory allocation routines will be thread-safe.

To complement the standard APIs the memory allocation package provides support for custom memory pools.

C library functions

The main dynamic memory allocation routines defined by standard C is malloc(): this allocates a chunk of memory from the heap at least as large as the amount requested, satisfying any alignment restrictions imposed by the architecture. The initial contents of the allocated chunk is undefined. If the heap cannot satisfy the allocation request then a null pointer will be returned.

The standard does not define what happens when malloc() is passed a size of 0. In eCos this is controlled by a configuration option CYGSEM_MEMALLOC_MALLOC_ZERO_RETURNS_NULL. By default the option is disabled and an argument of 0 will still result in an allocation of the smallest size supported by the memory allocator. If the option is enabled then a null pointer will be returned instead.

calloc() tries to allocate a memory chunk of at least nmemb*size bytes. If the allocation succeeds then the memory will be filled with zeroes. Otherwise a null pointer is returned.

realloc() tries to change the size of an existing allocation while leaving the contents unchanged. This may involve resizing the chunk in situ, or it may involve a malloc()/memcpy()/free() sequence. If the operation succeeds a valid pointer will be returned, which may or may not be the same as the original pointer. If the operation fails then a null pointer will be returned and the original data remains intact. There are two special cases: if the ptr argument is a null pointer then realloc() will act like malloc(); otherwise if the size argument is 0 then realloc() will act like free().

free() takes a pointer previously returned by malloc(), calloc() or realloc() and returns the memory to the heap.

mallinfo() is not defined by the C standard but is provided for compatibility with other systems. It returns information about the current state of the heap in the form of a mallinfo structure:

struct mallinfo {
    int arena;    /* total size of memory arena */
    int ordblks;  /* number of ordinary memory blocks */
    int uordblks; /* space used by ordinary memory blocks */
    int fordblks; /* space free for ordinary blocks */
    int maxfree;  /* size of largest free block */
};
      

arena gives the total heap size. ordblks and uordblks give some information on current allocations, and fordblks indicates how much is left. The remaining memory may be fragmented so maxfree indicates the largest allocation that is currently possible. A mallinfo structure contains a number of other fields but those are not used by eCos and exist only for compatibility reasons.

C++ operators

C++ applications can use the standard C library routines for dynamic memory allocation, but it is more common to use the C++ new and delete operators. There are a number of different implementations of these:

  1. The infrastructure package contains empty versions of the delete operators which do not interact with the system heap in any way. This is necessary because of the way the g++ compiler handles certain language constructs. Whenever there is a class with a virtual destructor the generated code always contains a reference to the delete operator. The linker is unable to delete this. Therefore if the application uses such a class, directly or indirectly, the final executable will contain a delete implementation - even if there is no dynamic allocation. The usual delete operator would pull in the system heap and hence the memory allocation package, significantly increasing code size for no good reason. Providing an empty delete avoids this.

    Unfortunately this solution is imperfect. If instead the application does want to create and destroy objects on the heap, by default the empty delete operators will still get linked in and the memory never gets freed. It is not possible to handle both scenarios cleanly with current tools, so instead the application developer has to configure eCos appropriately. To suppress the empty delete operators the configuration option CYGFUN_INFRA_EMPTY_DELETE_FUNCTIONS should be disabled. If an eCos package performs dynamic memory allocation using C++ new and delete then it should automatically disable this option via a CDL requires property.

  2. The next implementation of new and delete comes in the C++ support library libsupc++.a, which is normally available as part of the GNU toolchain. These versions are straightforward, simply calling malloc() and free() to access the system heap. When linking an application with an eCos linker script the C++ support library is searched automatically, so application developers only need to worry about disabling CYGFUN_INFRA_EMPTY_DELETE_FUNCTIONS.

  3. Finally the memory allocation package can also provide implementations of the C++ operators. These access the system heap directly rather than going via malloc() and free() so can be marginally faster, but at the cost of some increased code size. There is a significant difference of the system is configured for collecting memory debug data. These implementations of new and delete integrate directly with the debug data code, so more information will be collected. This is especially useful on architectures where the compiler only provides limited backtrace support.

    The configuration option CYGFUN_MEMALLOC_MALLOC_CXX_OPERATORS controls whether or not the memory allocation package's versions of the C++ operators get built. By default this option is disabled, unless CYGDBG_MEMALLOC_DEBUG_DEBUGDATA is enabled. When linking an application with an eCos linker script these operators will automatically be used in preference to the ones in libsupc++.a.

Debug Support

An application that uses dynamic memory allocation is often more difficult to debug than one that relies entirely on static allocation. To assist developers the memory allocation package provides a number of debugging facilities. The main one involves the collection of additional debug data for every memory allocation. This debug data can be transferred to the host and analyzed using a custom tool ecosmdd. Full documentation on this is provided elsewhere.

This package also provides support for some simple debugging techniques which can help detect certain problems. The first is memory guards: every allocated chunk is surrounded by a number of guard bytes. When the chunk is freed, using free() or the appropriate C++ delete operator, the guards are checked and any discrepancy is treated as an assertion failure. The head guard can detect certain buffer overflows in the previously allocated chunk. If the chunk contains a thread stack and the architecture involves a descending stack then the head guard can also detect stack overflows. The tail guard can detect certain overflows in the chunk being freed and underflows in the next chunk. The guards are reset during a free operation, which can help to catch attempts to free the same chunk twice. Guard checks only happen during a free operation so a corruption may go undetected for a long time, possibly too long, but are still better to never detecting corruption.

Memory guards are controlled by the configuration option CYGDBG_MEMALLOC_MALLOC_DEBUG_GUARDS. By default they are enabled if system-wide debugging (CYGPKG_INFRA_DEBUG) is enabled, otherwise disabled.

The second debugging technique is to fill memory chunks when they are freed. This helps to catch some attempts to use a pointer which is no longer valid. Such problems are particularly common in multi-threaded applications where thread A frees a chunk that thread B is still using. When freed chunks are filled thread B will suddenly see spurious data, often resulting in bus errors or other exceptions. The relevant configuration option is CYGDBG_MEMALLOC_MALLOC_DEBUG_FILL_FREE, which by default is also enabled if CYGPKG_INFRA_DEBUG is enabled. The option's value determines what the freed chunk gets filled with, usually 0xff.

2017-02-09
Documentation license for this page: Open Publication License