Zakero's C++ Header Libraries
A collection of reusable C++ libraries
|
Zakero MemoryPool. More...
Go to the source code of this file.
Classes | |
class | zakero::MemoryPool |
A pool of memory. More... | |
struct | zakero::MemoryPool::Segment |
Data that defines a segment. More... | |
Macros | |
#define | ZAKERO_MEMORYPOOL_IMPLEMENTATION |
Activate the implementation code. More... | |
Functions | |
std::string | zakero::to_string (const MemoryPool::VectorSegment &segment) noexcept |
Convert VectorSegment into a JSON formated string. More... | |
API | Dependencies | TL;DR | What Is It? | Why Use It? | How To Use It? | Version |
Here, you will find information about and how to add the Zakero_MemoryPool to your project.
This library will provide a memory pool for your application.
To use:
The Zakero MemoryPool library will create and manage a region of memory. From this pool of memory, sections of memory can be allocated and freed. When allocated, the memory is identified by an offset into the region of memory instead of a pointer. Programs are expected to be "good citizens" by using the offset and not writing outside of their allocated area.
The region of memory is anchored to an anonymous file descriptor. The benefit of using the file description is that the Operating System can remap the file to a larger area as needed. And since all allocated memory uses an offset, no pointers end up pointing to a bad location.
As with many things, there are benefits and draw backs to using a memory pool. For the MemoryPool object they are:
Benefits
new
or malloc
Draw Backs
To put things into perspective, allocating memory is a very expensive operation. Using the MemoryPool means this operation only needs to happen once. Allocating memory from the MemoryPool just needs to scan the memory region that can hold the request size. Even for extremely large memory pools, this is a very fast operation. Requiring the size (in bytes) to be allocated from the MemoryPool contributes to the speed of the allocation.
Since the MemoryPool uses a Unix File Descriptor for the memory region, only that Unix File Descriptor must be shared between processes to access the entire MemoryPool data.
As a result of using a Unix File Descriptor, allocating memory returns an offset into the MemoryPool data. When the memory region expands in the MemoryPool, the location of the "file" may change. Using offsets into the data negates the problem of pointing to invalid memory. Unfortunately, programming uses pointers instead of offsets. MemoryPool does provide a way to be notified when the memory region moves so the pointers an application is using can be updated.
Unless C++'s Placement New is being used extensively, the developer must be fully aware of where they are in their area of the memory region so that other data is not over written.
Placement New will break when the memory region moves.
Memory fragmentation already happens in most applications. The impact of the fragmentation is not felt due to huge amounts of memory in today's computers. However, for small amounts of memory fragmentation becomes a larger issue. Over the course of an application's life-time, it may allocate and free memory many times. At some point in time, if a large block of memory is requested, that allocation may fail because a contiguous region of memory is not available. This is the problem that plagues memory pools.
If the benefits out-weigh the draw backs for your application, then the MemoryPool is what you need.
This implementation is limited to signed 32-bit file sizes.
Step 0
Your compiler must support at least the C++20 standard. The location of the Zakero_*.h
header files must be in your compiler's include path.
Step 1
The first step is to select which C++ source code file will contain the Zakero MemoryPool implementation. Once the location has been determined, add the following to that file:
The macro ZAKERO_MEMORYPOOL_IMPLEMENTATION tells the header file to include the implementation of the MemoryPool.
In all other files that will use the MemoryPool, they need to include the header.
Step 2
After creating a MemoryPool, it must be initialized before it can be used.
Once that is done, you can freely allocate and free memory from the MemoryPool.
This is an example of creating two std::array's that are backed by the MemoryPool.
0.9.0
std::error_code
instead of std::error_code
0.8.0
0.7.0
0.6.0
Add support for huge file sizes (64-bit / huge table fs)
Be able to defrag the memory pool
Pass a lambda to the resize() method so that how the memory is moved can be controlled. For example, if the memory was holding a texture, the texture should be "clipped" or "zero'ed" space added around the existing data.
Be able to initialize a MemoryPool with a Unix File Descriptor and the file size.
struct zakero::MemoryPool::Segment |
#define ZAKERO_MEMORYPOOL_IMPLEMENTATION |
Defining this macro will cause the zakero::MemoryPool implementation to be included. This should only be done once, since compiler and/or linker errors will typically be generated if more than a single implementation is found.
|
noexcept |
segment | The value to convert |