Make sure DefaultAllocator and SingleFrameAllocator returned 16-bytes aligned memory
This commit is contained in:
parent
e0ff5b5fd2
commit
ff25e839f3
|
@ -6,6 +6,9 @@
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- The library must now be compiled with C++ 17 compiler
|
||||||
|
- If the user sets its custom allocator, the return allocated memory must now be 16 bytes aligned
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Minimum cmake version required
|
# Minimum cmake version required
|
||||||
cmake_minimum_required(VERSION 3.8)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
# Project configuration
|
# Project configuration
|
||||||
project(ReactPhysics3D VERSION 0.9.0 LANGUAGES CXX)
|
project(ReactPhysics3D VERSION 0.9.0 LANGUAGES CXX)
|
||||||
|
@ -242,7 +242,7 @@ add_library(reactphysics3d ${REACTPHYSICS3D_HEADERS} ${REACTPHYSICS3D_SOURCES})
|
||||||
add_library(ReactPhysics3D::reactphysics3d ALIAS reactphysics3d)
|
add_library(ReactPhysics3D::reactphysics3d ALIAS reactphysics3d)
|
||||||
|
|
||||||
# C++11 compiler features
|
# C++11 compiler features
|
||||||
target_compile_features(reactphysics3d PUBLIC cxx_std_11)
|
target_compile_features(reactphysics3d PUBLIC cxx_std_17)
|
||||||
set_target_properties(reactphysics3d PROPERTIES CXX_EXTENSIONS OFF)
|
set_target_properties(reactphysics3d PROPERTIES CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
# Library headers
|
# Library headers
|
||||||
|
|
|
@ -129,6 +129,9 @@ constexpr uint16 NB_MAX_CONTACT_POINTS_IN_POTENTIAL_MANIFOLD = 256;
|
||||||
/// Distance threshold to consider that two contact points in a manifold are the same
|
/// Distance threshold to consider that two contact points in a manifold are the same
|
||||||
constexpr decimal SAME_CONTACT_POINT_DISTANCE_THRESHOLD = decimal(0.01);
|
constexpr decimal SAME_CONTACT_POINT_DISTANCE_THRESHOLD = decimal(0.01);
|
||||||
|
|
||||||
|
/// Global alignment (in bytes) that all allocators must enforce
|
||||||
|
constexpr uint8 GLOBAL_ALIGNMENT = 16;
|
||||||
|
|
||||||
/// Current version of ReactPhysics3D
|
/// Current version of ReactPhysics3D
|
||||||
const std::string RP3D_VERSION = std::string("0.9.0");
|
const std::string RP3D_VERSION = std::string("0.9.0");
|
||||||
|
|
||||||
|
|
|
@ -28,15 +28,19 @@
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include <reactphysics3d/memory/MemoryAllocator.h>
|
#include <reactphysics3d/memory/MemoryAllocator.h>
|
||||||
|
#include <reactphysics3d/configuration.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
/// ReactPhysics3D namespace
|
/// ReactPhysics3D namespace
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
// Class DefaultAllocator
|
// Class DefaultAllocator
|
||||||
/**
|
/**
|
||||||
* This class represents a default memory allocator that uses default malloc/free methods
|
* This class represents a default memory allocator that uses standard C++ functions
|
||||||
|
* to allocated 16-bytes aligned memory.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
class DefaultAllocator : public MemoryAllocator {
|
class DefaultAllocator : public MemoryAllocator {
|
||||||
|
|
||||||
|
@ -49,15 +53,33 @@ class DefaultAllocator : public MemoryAllocator {
|
||||||
DefaultAllocator& operator=(DefaultAllocator& allocator) = default;
|
DefaultAllocator& operator=(DefaultAllocator& allocator) = default;
|
||||||
|
|
||||||
/// Allocate memory of a given size (in bytes) and return a pointer to the
|
/// Allocate memory of a given size (in bytes) and return a pointer to the
|
||||||
/// allocated memory.
|
/// allocated memory. The returned allocated memory must be 16 bytes aligned.
|
||||||
virtual void* allocate(size_t size) override {
|
virtual void* allocate(size_t size) override {
|
||||||
|
|
||||||
return std::malloc(size);
|
// If compiler is Visual Studio
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
// Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17
|
||||||
|
return _alligned_malloc(size, GLOBAL_ALIGNMENT);
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Return 16-bytes aligned memory
|
||||||
|
return std::aligned_alloc(GLOBAL_ALIGNMENT, size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release previously allocated memory.
|
/// Release previously allocated memory.
|
||||||
virtual void release(void* pointer, size_t /*size*/) override {
|
virtual void release(void* pointer, size_t /*size*/) override {
|
||||||
std::free(pointer);
|
|
||||||
|
// If compiler is Visual Studio
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
// Visual Studio doesn't not support standard std:aligned_alloc() method from c++ 17
|
||||||
|
return _aligned_free(GLOBAL_ALIGNMENT, pointer);
|
||||||
|
#else
|
||||||
|
|
||||||
|
return std::free(pointer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ class MemoryAllocator {
|
||||||
MemoryAllocator& operator=(MemoryAllocator& allocator) = default;
|
MemoryAllocator& operator=(MemoryAllocator& allocator) = default;
|
||||||
|
|
||||||
/// Allocate memory of a given size (in bytes) and return a pointer to the
|
/// Allocate memory of a given size (in bytes) and return a pointer to the
|
||||||
/// allocated memory.
|
/// allocated memory. The return allocated memory must be 16 bytes aligned.
|
||||||
virtual void* allocate(size_t size)=0;
|
virtual void* allocate(size_t size)=0;
|
||||||
|
|
||||||
/// Release previously allocated memory.
|
/// Release previously allocated memory.
|
||||||
|
|
|
@ -104,14 +104,18 @@ class MemoryManager {
|
||||||
// Allocate memory of a given type
|
// Allocate memory of a given type
|
||||||
RP3D_FORCE_INLINE void* MemoryManager::allocate(AllocationType allocationType, size_t size) {
|
RP3D_FORCE_INLINE void* MemoryManager::allocate(AllocationType allocationType, size_t size) {
|
||||||
|
|
||||||
|
void* allocatedMemory = nullptr;
|
||||||
|
|
||||||
switch (allocationType) {
|
switch (allocationType) {
|
||||||
case AllocationType::Base: return mBaseAllocator->allocate(size);
|
case AllocationType::Base: allocatedMemory = mBaseAllocator->allocate(size); break;
|
||||||
case AllocationType::Pool: return mPoolAllocator.allocate(size);
|
case AllocationType::Pool: allocatedMemory = mPoolAllocator.allocate(size); break;
|
||||||
case AllocationType::Heap: return mHeapAllocator.allocate(size);
|
case AllocationType::Heap: allocatedMemory = mHeapAllocator.allocate(size); break;
|
||||||
case AllocationType::Frame: return mSingleFrameAllocator.allocate(size);
|
case AllocationType::Frame: allocatedMemory = mSingleFrameAllocator.allocate(size); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
assert(allocatedMemory == nullptr || reinterpret_cast<uintptr_t>(allocatedMemory) % 16 == 0);
|
||||||
|
|
||||||
|
return allocatedMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release previously allocated memory.
|
// Release previously allocated memory.
|
||||||
|
|
|
@ -81,13 +81,16 @@ class PoolAllocator : public MemoryAllocator {
|
||||||
/// Number of heaps
|
/// Number of heaps
|
||||||
static const int NB_HEAPS = 128;
|
static const int NB_HEAPS = 128;
|
||||||
|
|
||||||
|
/// Minimum unit size
|
||||||
|
static const size_t MIN_UNIT_SIZE = 16;
|
||||||
|
|
||||||
/// Maximum memory unit size. An allocation request of a size smaller or equal to
|
/// Maximum memory unit size. An allocation request of a size smaller or equal to
|
||||||
/// this size will be handled using the small block allocator. However, for an
|
/// this size will be handled using the small block allocator. However, for an
|
||||||
/// allocation request larger than the maximum block size, the standard malloc()
|
/// allocation request larger than the maximum block size, the standard malloc()
|
||||||
/// will be used.
|
/// will be used.
|
||||||
static const size_t MAX_UNIT_SIZE = 1024;
|
static const size_t MAX_UNIT_SIZE = NB_HEAPS * MIN_UNIT_SIZE;
|
||||||
|
|
||||||
/// Size a memory chunk
|
/// Size of a memory chunk
|
||||||
static const size_t BLOCK_SIZE = 16 * MAX_UNIT_SIZE;
|
static const size_t BLOCK_SIZE = 16 * MAX_UNIT_SIZE;
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
|
@ -45,10 +45,6 @@ class SingleFrameAllocator : public MemoryAllocator {
|
||||||
|
|
||||||
// -------------------- Constants -------------------- //
|
// -------------------- Constants -------------------- //
|
||||||
|
|
||||||
/// Number of frames to wait before shrinking the allocated
|
|
||||||
/// memory if too much is allocated
|
|
||||||
static const int NB_FRAMES_UNTIL_SHRINK = 120;
|
|
||||||
|
|
||||||
/// Initial size (in bytes) of the single frame allocator
|
/// Initial size (in bytes) of the single frame allocator
|
||||||
size_t INIT_SINGLE_FRAME_ALLOCATOR_NB_BYTES = 1048576; // 1Mb
|
size_t INIT_SINGLE_FRAME_ALLOCATOR_NB_BYTES = 1048576; // 1Mb
|
||||||
|
|
||||||
|
@ -69,13 +65,6 @@ class SingleFrameAllocator : public MemoryAllocator {
|
||||||
/// Pointer to the next available memory location in the buffer
|
/// Pointer to the next available memory location in the buffer
|
||||||
size_t mCurrentOffset;
|
size_t mCurrentOffset;
|
||||||
|
|
||||||
/// Current number of frames since we detected too much memory
|
|
||||||
/// is allocated
|
|
||||||
size_t mNbFramesTooMuchAllocated;
|
|
||||||
|
|
||||||
/// True if we need to allocate more memory in the next reset() call
|
|
||||||
bool mNeedToAllocatedMore;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
|
@ -175,7 +175,12 @@ void* HeapAllocator::allocate(size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a pointer to the memory area inside the unit
|
// Return a pointer to the memory area inside the unit
|
||||||
return static_cast<void*>(reinterpret_cast<unsigned char*>(currentUnit) + sizeof(MemoryUnitHeader));
|
void* allocatedMemory = static_cast<void*>(reinterpret_cast<unsigned char*>(currentUnit) + sizeof(MemoryUnitHeader));
|
||||||
|
|
||||||
|
// Check that allocated memory is 16-bytes aligned
|
||||||
|
assert(reinterpret_cast<uintptr_t>(allocatedMemory) % GLOBAL_ALIGNMENT == 0);
|
||||||
|
|
||||||
|
return allocatedMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release previously allocated memory.
|
// Release previously allocated memory.
|
||||||
|
@ -251,6 +256,9 @@ void HeapAllocator::reserve(size_t sizeToAllocate) {
|
||||||
void* memory = mBaseAllocator.allocate(sizeToAllocate + sizeof(MemoryUnitHeader));
|
void* memory = mBaseAllocator.allocate(sizeToAllocate + sizeof(MemoryUnitHeader));
|
||||||
assert(memory != nullptr);
|
assert(memory != nullptr);
|
||||||
|
|
||||||
|
// Check that allocated memory is 16-bytes aligned
|
||||||
|
assert(reinterpret_cast<uintptr_t>(memory) % GLOBAL_ALIGNMENT == 0);
|
||||||
|
|
||||||
// Create a new memory unit for the allocated memory
|
// Create a new memory unit for the allocated memory
|
||||||
MemoryUnitHeader* memoryUnit = new (memory) MemoryUnitHeader(sizeToAllocate, nullptr, mMemoryUnits, false);
|
MemoryUnitHeader* memoryUnit = new (memory) MemoryUnitHeader(sizeToAllocate, nullptr, mMemoryUnits, false);
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ PoolAllocator::PoolAllocator(MemoryAllocator& baseAllocator) : mBaseAllocator(ba
|
||||||
// Initialize the array that contains the sizes of the memory units that will
|
// Initialize the array that contains the sizes of the memory units that will
|
||||||
// be allocated in each different heap
|
// be allocated in each different heap
|
||||||
for (uint i=0; i < NB_HEAPS; i++) {
|
for (uint i=0; i < NB_HEAPS; i++) {
|
||||||
mUnitSizes[i] = (i+1) * 8;
|
mUnitSizes[i] = (i+1) * MIN_UNIT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the lookup table that maps the size to allocated to the
|
// Initialize the lookup table that maps the size to allocated to the
|
||||||
|
@ -116,7 +116,12 @@ void* PoolAllocator::allocate(size_t size) {
|
||||||
if (size > MAX_UNIT_SIZE) {
|
if (size > MAX_UNIT_SIZE) {
|
||||||
|
|
||||||
// Allocate memory using default allocation
|
// Allocate memory using default allocation
|
||||||
return mBaseAllocator.allocate(size);
|
void* allocatedMemory = mBaseAllocator.allocate(size);
|
||||||
|
|
||||||
|
// Check that allocated memory is 16-bytes aligned
|
||||||
|
assert(reinterpret_cast<uintptr_t>(allocatedMemory) % GLOBAL_ALIGNMENT == 0);
|
||||||
|
|
||||||
|
return allocatedMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the index of the heap that will take care of the allocation request
|
// Get the index of the heap that will take care of the allocation request
|
||||||
|
@ -129,7 +134,13 @@ void* PoolAllocator::allocate(size_t size) {
|
||||||
// Return a pointer to the memory unit
|
// Return a pointer to the memory unit
|
||||||
MemoryUnit* unit = mFreeMemoryUnits[indexHeap];
|
MemoryUnit* unit = mFreeMemoryUnits[indexHeap];
|
||||||
mFreeMemoryUnits[indexHeap] = unit->nextUnit;
|
mFreeMemoryUnits[indexHeap] = unit->nextUnit;
|
||||||
return unit;
|
|
||||||
|
void* allocatedMemory = static_cast<void*>(unit);
|
||||||
|
|
||||||
|
// Check that allocated memory is 16-bytes aligned
|
||||||
|
assert(reinterpret_cast<uintptr_t>(allocatedMemory) % GLOBAL_ALIGNMENT == 0);
|
||||||
|
|
||||||
|
return allocatedMemory;
|
||||||
}
|
}
|
||||||
else { // If there is no more free memory units in the corresponding heap
|
else { // If there is no more free memory units in the corresponding heap
|
||||||
|
|
||||||
|
@ -170,8 +181,13 @@ void* PoolAllocator::allocate(size_t size) {
|
||||||
mFreeMemoryUnits[indexHeap] = newBlock->memoryUnits->nextUnit;
|
mFreeMemoryUnits[indexHeap] = newBlock->memoryUnits->nextUnit;
|
||||||
mNbCurrentMemoryBlocks++;
|
mNbCurrentMemoryBlocks++;
|
||||||
|
|
||||||
|
void* allocatedMemory = newBlock->memoryUnits;
|
||||||
|
|
||||||
|
// Check that allocated memory is 16-bytes aligned
|
||||||
|
assert(reinterpret_cast<uintptr_t>(allocatedMemory) % GLOBAL_ALIGNMENT == 0);
|
||||||
|
|
||||||
// Return the pointer to the first memory unit of the new allocated block
|
// Return the pointer to the first memory unit of the new allocated block
|
||||||
return newBlock->memoryUnits;
|
return allocatedMemory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ using namespace reactphysics3d;
|
||||||
// Constructor
|
// Constructor
|
||||||
SingleFrameAllocator::SingleFrameAllocator(MemoryAllocator& baseAllocator) : mBaseAllocator(baseAllocator),
|
SingleFrameAllocator::SingleFrameAllocator(MemoryAllocator& baseAllocator) : mBaseAllocator(baseAllocator),
|
||||||
mTotalSizeBytes(INIT_SINGLE_FRAME_ALLOCATOR_NB_BYTES),
|
mTotalSizeBytes(INIT_SINGLE_FRAME_ALLOCATOR_NB_BYTES),
|
||||||
mCurrentOffset(0), mNbFramesTooMuchAllocated(0), mNeedToAllocatedMore(false) {
|
mCurrentOffset(0) {
|
||||||
|
|
||||||
// Allocate a whole block of memory at the beginning
|
// Allocate a whole block of memory at the beginning
|
||||||
mMemoryBufferStart = static_cast<char*>(mBaseAllocator.allocate(mTotalSizeBytes));
|
mMemoryBufferStart = static_cast<char*>(mBaseAllocator.allocate(mTotalSizeBytes));
|
||||||
|
@ -48,47 +48,71 @@ SingleFrameAllocator::~SingleFrameAllocator() {
|
||||||
mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes);
|
mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Allocate memory of a given size (in bytes) and return a pointer to the
|
// Allocate memory of a given size (in bytes) and return a pointer to the
|
||||||
// allocated memory.
|
// allocated memory. Allocated memory must be 16-bytes aligned.
|
||||||
void* SingleFrameAllocator::allocate(size_t size) {
|
void* SingleFrameAllocator::allocate(size_t size) {
|
||||||
|
|
||||||
// Lock the method with a mutex
|
// Lock the method with a mutex
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
|
// Allocate a little bit more memory to make sure we can return an aligned address
|
||||||
|
const size_t totalSize = size + GLOBAL_ALIGNMENT;
|
||||||
|
|
||||||
// Check that there is enough remaining memory in the buffer
|
// Check that there is enough remaining memory in the buffer
|
||||||
if (mCurrentOffset + size > mTotalSizeBytes) {
|
if (mCurrentOffset + totalSize > mTotalSizeBytes) {
|
||||||
|
|
||||||
// We need to allocate more memory next time reset() is called
|
const size_t previousTotalSizeBytes = mTotalSizeBytes;
|
||||||
mNeedToAllocatedMore = true;
|
|
||||||
|
|
||||||
// Return default memory allocation
|
// Multiply the total memory to allocate by two
|
||||||
return mBaseAllocator.allocate(size);
|
mTotalSizeBytes *= 2;
|
||||||
|
|
||||||
|
// Allocate a whole block of memory
|
||||||
|
void* allocatedMemory = mBaseAllocator.allocate(mTotalSizeBytes);
|
||||||
|
assert(allocatedMemory != nullptr);
|
||||||
|
|
||||||
|
// Check that allocated memory is 16-bytes aligned
|
||||||
|
assert(reinterpret_cast<uintptr_t>(allocatedMemory) % GLOBAL_ALIGNMENT == 0);
|
||||||
|
|
||||||
|
char* newMemoryBufferStart = static_cast<char*>(allocatedMemory);
|
||||||
|
|
||||||
|
// Copy the previous memory bloc to new new location
|
||||||
|
memcpy(newMemoryBufferStart, mMemoryBufferStart, previousTotalSizeBytes);
|
||||||
|
|
||||||
|
// Release the memory allocated at the beginning
|
||||||
|
mBaseAllocator.release(mMemoryBufferStart, previousTotalSizeBytes);
|
||||||
|
|
||||||
|
mMemoryBufferStart = newMemoryBufferStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next available memory location
|
// Next available memory location
|
||||||
void* nextAvailableMemory = mMemoryBufferStart + mCurrentOffset;
|
void* nextAvailableMemory = mMemoryBufferStart + mCurrentOffset;
|
||||||
|
|
||||||
|
// Take care of alignment to make sure that we always return an address to the
|
||||||
|
// enforce the global alignment of the library
|
||||||
|
uintptr_t currentAdress = reinterpret_cast<uintptr_t>(nextAvailableMemory);
|
||||||
|
|
||||||
|
// Calculate the adjustment by masking off the lower bits of the address, to determine how "misaligned" it is.
|
||||||
|
size_t mask = GLOBAL_ALIGNMENT - 1;
|
||||||
|
uintptr_t misalignment = currentAdress & mask;
|
||||||
|
ptrdiff_t alignmentOffset = GLOBAL_ALIGNMENT - misalignment;
|
||||||
|
|
||||||
|
// Compute the aligned address
|
||||||
|
uintptr_t alignedAdress = currentAdress + alignmentOffset;
|
||||||
|
nextAvailableMemory = reinterpret_cast<void*>(alignedAdress);
|
||||||
|
|
||||||
// Increment the offset
|
// Increment the offset
|
||||||
mCurrentOffset += size;
|
mCurrentOffset += totalSize;
|
||||||
|
|
||||||
|
// Check that allocated memory is 16-bytes aligned
|
||||||
|
assert(reinterpret_cast<uintptr_t>(nextAvailableMemory) % GLOBAL_ALIGNMENT == 0);
|
||||||
|
|
||||||
// Return the next available memory location
|
// Return the next available memory location
|
||||||
return nextAvailableMemory;
|
return nextAvailableMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release previously allocated memory.
|
// Release previously allocated memory.
|
||||||
void SingleFrameAllocator::release(void* pointer, size_t size) {
|
void SingleFrameAllocator::release(void* /*pointer*/, size_t /*size*/) {
|
||||||
|
|
||||||
// Lock the method with a mutex
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
|
|
||||||
// If allocated memory is not within the single frame allocation range
|
|
||||||
char* p = static_cast<char*>(pointer);
|
|
||||||
if (p < mMemoryBufferStart || p > mMemoryBufferStart + mTotalSizeBytes) {
|
|
||||||
|
|
||||||
// Use default deallocation
|
|
||||||
mBaseAllocator.release(pointer, size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the marker of the current allocated memory
|
// Reset the marker of the current allocated memory
|
||||||
|
@ -97,48 +121,6 @@ void SingleFrameAllocator::reset() {
|
||||||
// Lock the method with a mutex
|
// Lock the method with a mutex
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
// If too much memory is allocated
|
|
||||||
if (mCurrentOffset < mTotalSizeBytes / 2) {
|
|
||||||
|
|
||||||
mNbFramesTooMuchAllocated++;
|
|
||||||
|
|
||||||
if (mNbFramesTooMuchAllocated > NB_FRAMES_UNTIL_SHRINK) {
|
|
||||||
|
|
||||||
// Release the memory allocated at the beginning
|
|
||||||
mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes);
|
|
||||||
|
|
||||||
// Divide the total memory to allocate by two
|
|
||||||
mTotalSizeBytes /= 2;
|
|
||||||
if (mTotalSizeBytes == 0) mTotalSizeBytes = 1;
|
|
||||||
|
|
||||||
// Allocate a whole block of memory at the beginning
|
|
||||||
mMemoryBufferStart = static_cast<char*>(mBaseAllocator.allocate(mTotalSizeBytes));
|
|
||||||
assert(mMemoryBufferStart != nullptr);
|
|
||||||
|
|
||||||
mNbFramesTooMuchAllocated = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mNbFramesTooMuchAllocated = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we need to allocate more memory
|
|
||||||
if (mNeedToAllocatedMore) {
|
|
||||||
|
|
||||||
// Release the memory allocated at the beginning
|
|
||||||
mBaseAllocator.release(mMemoryBufferStart, mTotalSizeBytes);
|
|
||||||
|
|
||||||
// Multiply the total memory to allocate by two
|
|
||||||
mTotalSizeBytes *= 2;
|
|
||||||
|
|
||||||
// Allocate a whole block of memory at the beginning
|
|
||||||
mMemoryBufferStart = static_cast<char*>(mBaseAllocator.allocate(mTotalSizeBytes));
|
|
||||||
assert(mMemoryBufferStart != nullptr);
|
|
||||||
|
|
||||||
mNeedToAllocatedMore = false;
|
|
||||||
mNbFramesTooMuchAllocated = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the current offset at the beginning of the block
|
// Reset the current offset at the beginning of the block
|
||||||
mCurrentOffset = 0;
|
mCurrentOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user