A pool of memory.
More...
|
| MemoryPool (const std::string &) noexcept |
| Constructor. More...
|
|
| ~MemoryPool () noexcept |
| Destructor. More...
|
|
std::error_condition | init (const size_t, const bool=false, const MemoryPool::Alignment=MemoryPool::Alignment::Bits_64) noexcept |
| Initialize the MemoryPool. More...
|
|
int | fd () const noexcept |
| The backing file descriptor. More...
|
|
size_t | size () const noexcept |
| The size of the memory pool. More...
|
|
void | sizeOnChange (MemoryPool::LambdaSize) noexcept |
| Set the Size Event callback. More...
|
|
off_t | alloc (const size_t) noexcept |
| Allocate memory from the pool. More...
|
|
off_t | alloc (const size_t, std::error_condition &) noexcept |
| Allocate memory from the pool. More...
|
|
off_t | alloc (size_t, uint8_t) noexcept |
| Allocate memory from the pool. More...
|
|
off_t | alloc (size_t, uint8_t, std::error_condition &) noexcept |
| Allocate memory from the pool. More...
|
|
off_t | alloc (size_t, uint32_t) noexcept |
| Allocate memory from the pool. More...
|
|
off_t | alloc (size_t, uint32_t, std::error_condition &) noexcept |
| Allocate memory from the pool. More...
|
|
void | free (off_t &) noexcept |
| Free allocated memory. More...
|
|
off_t | realloc (off_t, size_t) noexcept |
| Change the size of allocated memory. More...
|
|
off_t | realloc (off_t, size_t, std::error_condition &) noexcept |
| Change the size of allocated memory. More...
|
|
uint8_t * | addressOf (off_t) const noexcept |
| Convert an offset into a pointer. More...
|
|
void | onRemap (MemoryPool::LambdaAddressMap) noexcept |
| Set the Remap Event callback. More...
|
|
std::string | dump (size_t, size_t) const noexcept |
| Output the internal state. More...
|
|
Refer to Zakero_MemoryPool.h to learn how to include this library.
This object will create a region of memory and provide an interface to allocate from that memory.
◆ Alignment
When allocating memory from the MemoryPool, this enum determines which byte-boundary will be used.
◆ MemoryPool()
zakero::MemoryPool::MemoryPool |
( |
const std::string & |
name | ) |
|
|
noexcept |
Create a new instance of the MemoryPool. The provide file name
is not the name of a file on the file system. The file name
will only exist in RAM with an optional backing store in swap in available.
- Example
- Note
- If ZAKERO_MEMORYPOOL_PROFILER is defined, then ZAKERO_PROFILER_INIT_METADATA will be called to setup the profiler.
- Parameters
-
◆ ~MemoryPool()
zakero::MemoryPool::~MemoryPool |
( |
| ) |
|
|
noexcept |
Release all allocated resources.
◆ init()
std::error_condition zakero::MemoryPool::init |
( |
const size_t |
size, |
|
|
const bool |
expandable = false , |
|
|
const MemoryPool::Alignment |
alignment = MemoryPool::Alignment::Bits_64 |
|
) |
| |
|
noexcept |
The MemoryPool must be initialized before it can be used. At a minimum, the size of the MemoryPool must be specified in bytes.
The maximum allowable size is MemoryPool::Size_Max which represents the largest offset value supported by the MemoryPool. Your hardware configuration and/or operating system may lower this limit.
Setting the expandable
flag to true
will allow the MemoryPool to grow to a larger size. If an allocation request is made that is larger that the largest available contiguous space available, then the Memory Pool will expand just enough to accommodate the request.
The Byte Boundary of all the allocations for this MemoryPool object is specified by the alignment
.
- Note
- The size of the MemoryPool will never shrink.
- Example
#define KILOBYETS(size_) ((size_) * 1024)
#define MEGABYTES(size_) (KILOBYTES(size_) * 1024)
rgba_textures.init(MEGABYTES(32)
, false
, zakero::MemoryPool::Alignment::Bits_32
);
- Returns
- An error condition. If there was no error, then the value of the error condition will be
0
.
- Parameters
-
size | The initial size in bytes |
expandable | Allow the MemoryPool to expand |
alignment | The Byte Alignment |
◆ fd()
int zakero::MemoryPool::fd |
( |
| ) |
const |
|
noexcept |
If something needs to be able to map the same region of memory as this MemoryPool, then this method will provide the file descriptor to do it.
The entire MemoryPool will be accessible from the file descriptor.
- Example
uint8_t* mem_reader = (uint8_t*)mmap(nullptr
, memory_pool.size()
, PROT_READ
, MAP_SHARED | MAP_NORESERVE
, memory_pool.fd()
);
- See also
- MemoryPool::size()
- Returns
- The file descriptor.
◆ size()
size_t zakero::MemoryPool::size |
( |
| ) |
const |
|
noexcept |
The current size of the MemoryPool, in bytes, will be returned.
- Returns
- The size of the memory pool.
◆ sizeOnChange()
If the MemoryPool was configured to be able to dynamically expand as needed (see init()), then the provided lambda
will be called when the memory pool changes size. Using the sizeOnChange() method before calling init() will not cause the lambda to be executed when init() is called.
The lambda
will receive the new size, in bytes, of the memory pool.
- Example
memory_pool.init(1, true);
memory_pool.sizeOnChange([](size_t new_size)
{
std::cout << "Size: " << size_t << "\n";
});
off_t uno = memory_pool.alloc(256);
off_t dos = memory_pool.alloc(512);
- Note
- The MemoryPool will be in a "locked state" so any call from the lambda to a non-const MemoryPool method will block indefinitely.
- Parameters
-
◆ alloc() [1/6]
off_t zakero::MemoryPool::alloc |
( |
const size_t |
size | ) |
|
|
noexcept |
The requested size
(in bytes) will be allocated from the memory pool. If the memory could not be allocated, then -1
will be returned.
- Example
memory_pool.init(1024);
off_t data_offset = memory_pool.alloc(128);
- Note
- The contents of the memory is undefined.
- Returns
- The offset of the block of memory.
- Parameters
-
◆ alloc() [2/6]
off_t zakero::MemoryPool::alloc |
( |
const size_t |
size, |
|
|
std::error_condition & |
error |
|
) |
| |
|
noexcept |
The requested size
(in bytes) will be allocated from the memory pool. If the memory could not be allocated, then -1
will be returned and the reason will be stored in error
.
- Example
memory_pool.init(1024);
std::error_condition error;
off_t data_offset = memory_pool.alloc(512, error);
if(error.value() != 0)
{
std::cerr << "Error: " << error.message() << "\n";
}
- Note
- The contents of the memory is undefined.
- Returns
- The offset of the block of memory.
- Parameters
-
size | The size in bytes |
error | The error |
◆ alloc() [3/6]
off_t zakero::MemoryPool::alloc |
( |
size_t |
size, |
|
|
uint8_t |
value |
|
) |
| |
|
noexcept |
The requested size
(in bytes) will be allocated from the memory pool. If the memory could not be allocated, then -1
will be returned.
The every byte of the allocated memory will be set to value
.
- Example
memory_pool.init(1024);
off_t data_offset = memory_pool.alloc(512, uint8_t(0xa5));
- Returns
- The offset of the block of memory.
- Parameters
-
size | The size in bytes |
value | The fill value |
◆ alloc() [4/6]
off_t zakero::MemoryPool::alloc |
( |
size_t |
size, |
|
|
uint8_t |
value, |
|
|
std::error_condition & |
error |
|
) |
| |
|
noexcept |
The requested size
(in bytes) will be allocated from the memory pool. If the memory could not be allocated, then -1
will be returned and the reason will be stored in error
.
The every byte of the allocated memory will be set to value
.
- Example
memory_pool.init(1024);
std::error_condition error;
off_t data_offset = memory_pool.alloc(512, uint8_t(0xa5), error);
if(error.value() != 0)
{
std::cerr << "Error: " << error.message() << "\n";
}
- Returns
- The offset of the block of memory.
- Parameters
-
size | The size in bytes |
value | The fill value |
error | The error |
◆ alloc() [5/6]
off_t zakero::MemoryPool::alloc |
( |
size_t |
size, |
|
|
uint32_t |
value |
|
) |
| |
|
noexcept |
The requested size
(in bytes) will be allocated from the memory pool. If the memory could not be allocated, then -1
will be returned.
Every 32-bit in the allocated memory will be set to value
. Any bytes that leftover will be undefined. For example, 10 byte allocation with a value
of 0xaaaa5555. The last 2 bytes will be undefined. Memory Contents: aaaa5555aaaa5555??
- Example
memory_pool.init(1024);
off_t data_offset = memory_pool.alloc(512, uint32_t(0xaaaa5555));
- Returns
- The offset of the block of memory.
- Parameters
-
size | The size in bytes |
value | The fill value |
◆ alloc() [6/6]
off_t zakero::MemoryPool::alloc |
( |
size_t |
size, |
|
|
uint32_t |
value, |
|
|
std::error_condition & |
error |
|
) |
| |
|
noexcept |
The requested size
(in bytes) will be allocated from the memory pool. If the memory could not be allocated, then -1
will be returned and the reason will be stored in error
.
Every 32-bit in the allocated memory will be set to value
. Any bytes that leftover will be undefined. For example, 10 byte allocation with a value
of 0xaaaa5555. The last 2 bytes will be undefined. Memory Contents: aaaa5555aaaa5555??
- Example
memory_pool.init(1024);
std::error_condition error;
off_t data_offset = memory_pool.alloc(512, uint32_t(0xaaaa5555),
error);
if(error.value() != 0)
{
std::cerr << "Error: " << error.message() << "\n";
}
- Returns
- The offset of the block of memory.
- Parameters
-
size | The size in bytes |
value | The fill value |
error | The error |
◆ free()
void zakero::MemoryPool::free |
( |
off_t & |
offset | ) |
|
|
noexcept |
The allocated memory at the provided offset
will be free'ed. The offset
will be set to -1
.
If the offset
is not valid, its value will not be changed.
- Example
memory_pool.init(128);
off_t offset = memory_pool.alloc(64);
memory_pool.free(offset);
- Parameters
-
◆ realloc() [1/2]
off_t zakero::MemoryPool::realloc |
( |
off_t |
offset, |
|
|
size_t |
size |
|
) |
| |
|
noexcept |
This method is similar to std::realloc(), in that it will resize the allocated memory at the given offset
. If the resize was successful, the new offset will be returned.
The contents of the memory will be preserved.
The return value will be -1
if the allocated memory could not be resized.
- Example
memory_pool.init(128);
off_t offset = memory_pool.alloc(64);
offset = memory_pool.resize(offset, 96);
- Returns
- The offset of the resized memory location.
- Parameters
-
offset | The memory to resize |
size | The size in bytes |
◆ realloc() [2/2]
off_t zakero::MemoryPool::realloc |
( |
off_t |
offset, |
|
|
size_t |
size, |
|
|
std::error_condition & |
error |
|
) |
| |
|
noexcept |
This method is similar to std::realloc(), in that it will resize the allocated memory at the given offset
. If the resize was successful, the new offset will be returned.
The contents of the memory will be preserved.
The return value will be -1
if the allocated memory could not be resized and the reason will be stored in error
.
- Example
memory_pool.init(128);
off_t offset = memory_pool.alloc(64);
std::error_condition error;
auto new_offset = memory_pool.resize(offset, 96, error);
if(error(bool) == true)
{
std::cerr << "Error: " << error.message() << "\n";
}
else
{
offset = new_offset;
}
- Returns
- The offset of the resized memory location.
- Parameters
-
offset | The memory to resize |
size | The size in bytes |
error | The error |
◆ addressOf()
uint8_t * zakero::MemoryPool::addressOf |
( |
off_t |
offset | ) |
const |
|
noexcept |
The provided offset
will be converted into an address that can be de-referenced as a normal C-Style pointer. If the offset
is not valid, then nullptr
will be returned.
- Example
off_t offset = memory_pool.alloc(256);
uint8_t* ptr = memory_pool.addressOf(offset);
- Note
- If the MemoryPool expands and is relocated, the returned pointers will no longer be valid.
- See also
- onRemap()
- Returns
- An address
- Parameters
-
◆ onRemap()
There are times when the MemoryPool will move allocated data. When this happens, the provided lambda
will be called so that the caller will have an opportunity to update their pointers.
The lambda will receive a map of addresses where the key is the old address and the value is the new address.
If the MemoryPool was configured to be not expandable (see init()), then the MemoryPool will never have a need to move it's region of memory. Therefore, the lambda
will never be called and the pointers will never become invalid (unless the memory is freed).
- Example
uint8_t* secret = nullptr;
{
});
off_t secret_offset = memory_pool.alloc(512);
secret = memory_pool.addressOf(secret_offset);
- Note
- The MemoryPool will be in a "locked state" so any call from the lambda to a non-const MemoryPool method will block indefinitely.
- See also
- remap()
- Parameters
-
◆ remap()
Lookup the provided address
in the addr_map
and return the new address. If the address
was not in the addr_map
, the value of the address
will be returned.
- Note
- This is a convenience method whose only purpose is to improve the quality-of-life of the MemoryPool API.
- See also
- onRemap()
- Returns
- A memory address.
- Parameters
-
addr_map | A map of old/new addresses |
address | An old memory address |
◆ dump()
std::string zakero::MemoryPool::dump |
( |
size_t |
bytes_per_character, |
|
|
size_t |
characters_per_line |
|
) |
| const |
|
noexcept |
The internal state of the MemoryPool will be converted into a JSON formatted string. The JSON string will contain the following:
- The name of the anonymous file
- The size of the memory pool
- A list of segments and information about each segment
- A layout of memory usage
The content of the layout is controlled by the bytes_per_character
and characters_per_line
parameters.
- Example
memory_pool(512);
off_t o1 = memory_pool.alloc(64);
off_t o2 = memory_pool.alloc(64);
off_t o3 = memory_pool.alloc(128);
off_t o4 = memory_pool.alloc(256);
memory_pool.free(o2);
memory_pool.dump(1, 128);
- Returns
- The JSON formatted string.
- Parameters
-
bytes_per_character | Used to determine how many allocated bytes are represented by each character in the layout. |
characters_per_line | The length of each layout line. |
The documentation for this class was generated from the following file:
static uint8_t * remap(const MemoryPool::AddressMap &, uint8_t *) noexcept
Get the new memory address.
Definition: Zakero_MemoryPool.h:1364
std::map< uint8_t *, uint8_t * > AddressMap
A mapping of old addresses to new addresses.
Definition: Zakero_MemoryPool.h:260