Dynamic Memory Management

By far, the biggest performance bottleneck when decoding ASN.1 messages is the allocation of memory from the heap. Each call to new or malloc is very expensive.

The decoding functions must allocate memory because the sizes of many of the variables that make up a message are not known at compile time. For example, an OCTET STRING that does not contain a size constraint can be an indeterminate number of bytes in length.

ASN1C does two things by default to reduce dynamic memory allocations and improve decoding performance:

  1. Uses static variables wherever it can. Any BIT STRING, OCTET STRING, character string, or SEQUENCE OF or SET OF construct that contains a size constraint will result in the generation of a static array of elements sized to the max constraint bound.

  2. Uses a special nibble-allocation algorithm for allocating dynamic memory. This algorithm allocates memory in large blocks and then splits up these blocks on subsequent memory allocation requests. This results in fewer calls to the kernel to get memory. The downside is that one request for a few bytes of memory can result in a large block being allocated.

Common run-time functions are available for controlling the memory allocation process. First, the default size of a memory block as allocated by the nibble-allocation algorithm can be changed. By default, this value is set to 4K bytes. The run-time function rtMemSetDefBlkSize can be called to change this size. This takes a single argument - the value to which the size should be changed.

It is also possible to change the underlying functions called from within the memory management abstraction layer to obtain or free heap memory. By default, the standard C malloc, realloc, and free functions are used. These can be changed by calling the rtMemSetAllocFuncs function. This function takes as arguments function pointers to the allocate, reallocate, and free functions to be used in place of the standard C functions.

Another run-time memory management function that can improve performance is rtMemReset. This function is useful when decoding messages in a loop. It is used instead of rtMemFree at the bottom of the loop to make dynamic memory available for decoding the next message. The difference is that rtMemReset does not actually free the dynamic memory. It instead just resets the internal memory management parameters so that memory already allocated can be reused. Therefore, all the memory required to handle message decoding is normally allocated within the first few passes of the loop. From that point on, that memory is reused thereby making dynamic memory allocation a negligent issue in the overall performance of the decoder.

A more detailed explanation of these functions and other memory management functions can be found in the C/ C++Common Run-Time Library Reference Manual.