What makes this library different to others is its ability for memory re-allocation.
This section explains how it works and how it achieves best performances and less memory fragmentation vs others.
Sometimes application uses variable length of memory,
especially when number of (as an example) elements in not fully known in advance.
For the sake of this example, application anticipates ``12`` numbers (`integers`) but may (due to unknown reason in some cases) receive more than this.
If application needs to hold all received numbers, it may be necessary to:
* Option ``1``: Increase memory block size using reallocations
* Option ``2``: Use very big (do we know how big?) array, allocated statically or dynamically, which would hold all numbers at any time possible
..note::
LwMEM has been optimized to handle well option ``1``.
Application needs to define at least single region:
At first, manager had ``120`` bytes of available memory while after allocation of ``48`` bytes, it only left ``64`` bytes.
Effectively ``120 - 64 = 56`` bytes have been used to allocate ``48`` bytes of memory.
..note::
Every allocated block holds meta data. On test machine, ``sizeof(int) = 4`` therefore ``8`` bytes are used for metadata as ``56 - 12 * sizeof(int) = 8``. Size of meta data header depends on CPU architecture and may be different between architectures
Application got necessary memory for ``12`` integers. How to proceed when application needs to extend size for one more integer?
Easiest would be to:
#. Allocate new memory block with new size and check if allocation was successful
#. Manually copy content from old block to new block
Oooops! It is not anymore possible to allocate new block for new ``15`` integers as there was no available block with at least ``15 * sizeof(int) + metadata_size`` bytes of free memory.
..note::
With this reallocation approach, maximal size of application block is only ``50%`` of region size. This is not the most effective memory manager!
Fortunately there is a solution. Every time application wants to resize existing block, manager tries to manipulate existing block and shrink or expand it.
Shrink existing block
^^^^^^^^^^^^^^^^^^^^^
Easiest reallocation algorithm is when application wants to decrease size of previously allocated memory.
When this is the case, manager only needs to change the size of existing block to lower value.
* Size of all ``4`` blocks is ``24`` bytes; ``16`` for user data, ``8`` for metadata
* Reallocating block first time from ``16`` to ``12`` user data bytes did not affect internal memory structure
* It is not possible to create new empty block as it would be too small, only ``4`` bytes available, minimum is ``8`` bytes for meta data
* It is not possible to enlarge next empty block due to *current* and *next empty* do not create contiguous block
* Block is internally left unchanged
* Reallocating block second time to ``8`` bytes was a success
* Difference between old and new size is ``8`` bytes which is enough for new empty block
* Its size is ``8`` bytes, effectively ``0`` for user data due to meta size
Shrink existing block - summary
*******************************
When reallocating already allocated memory block, one of `3` cases will happen:
* Case ``1``: When *current* block and *next free* block could create contigouos block of memory, *current* block is decreased (size parameter) and *next free* is enlarged by the size difference
* Case ``2``: When difference between *current* size and *new* size is more or equal to minimal size for new empty block, new empty block is created with size ``current_size - new_size`` and added to list of free blocks
* Case ``3``: When difference between *current* size and *new* size is less than minimal size for new empty block, block is left unchanged
Enlarge existing block
^^^^^^^^^^^^^^^^^^^^^^
Now that you master procedure to shrink (or decrease) size of existing allocated memory block, it is time to understand how to enlarge it.
Things here are more complicated, however, they are still easy to understand.
Manager covers ``3`` potential cases:
* Case ``1``: Increase size of currently allocated block
* Case ``2``: Merge previous empty block with existing one and shift data up
* Case ``3``: Block before and after existing block together create contiguous block of memory
*Free block* after + *allocated block* create one big contiguous block
When application makes many allocations and frees of memory, there is a high risk of memory fragmentations.
Essentially small chunks of allocated memory prevent manager to allocate new, fresh, big block of memory.
When it comes to reallocating of existing block, it may happen that *first free block after* and *current block* create a contiguous block, but its combined size is not big enough. Same could happen with *last block before* + *current block*. However, it may be possible to combine *free block before* + *current block* + *free block after* current block together.