// // Copyright 2019 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // PoolAlloc.h: // Defines the class interface for PoolAllocator. //
// // This header defines an allocator that can be used to efficiently // allocate a large number of small requests for heap memory, with the // intention that they are not individually deallocated, but rather // collectively deallocated at one time. // // This simultaneously // // * Makes each individual allocation much more efficient; the // typical allocation is trivial. // * Completely avoids the cost of doing individual deallocation. // * Saves the trouble of tracking down and plugging a large class of leaks. // // Individual classes can use this allocator by supplying their own // new and delete methods. //
#include"angleutils.h" #include"common/debug.h"
namespace angle
{ class Allocation; class PageHeader;
// // There are several stacks. One is to track the pushing and popping // of the user, and not yet implemented. The others are simply a // repositories of free pages or used pages. // // Page stacks are linked together with a simple header at the beginning // of each allocation obtained from the underlying OS. Multi-page allocations // are returned to the OS. Individual page allocations are kept for future // re-use. // // The "page size" used is not, nor must it match, the underlying OS // page size. But, having it be about that size or equal to a set of // pages is likely most optimal. // class PoolAllocator : angle::NonCopyable
{ public: staticconstint kDefaultAlignment = sizeof(void *); // // Create PoolAllocator. If alignment is set to 1 byte then fastAllocate() // function can be used to make allocations with less overhead. //
PoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = kDefaultAlignment);
// // Don't call the destructor just to free up the memory, call pop() //
~PoolAllocator();
// // Initialize page size and alignment after construction // void initialize(int pageSize, int alignment);
// // Call push() to establish a new place to pop memory to. Does not // have to be called to get things started. // void push();
// // Call pop() to free all memory allocated since the last call to push(), // or if no last call to push, frees all memory since first allocation. // void pop();
// // Call popAll() to free all memory allocated. // void popAll();
// // Call allocate() to actually acquire memory. Returns 0 if no memory // available, otherwise a properly aligned pointer to 'numBytes' of memory. // void *allocate(size_t numBytes);
// // Call fastAllocate() for a faster allocate function that does minimal bookkeeping // preCondition: Allocator must have been created w/ alignment of 1
ANGLE_INLINE uint8_t *fastAllocate(size_t numBytes)
{ #ifdefined(ANGLE_DISABLE_POOL_ALLOC) returnreinterpret_cast<uint8_t *>(allocate(numBytes)); #else
ASSERT(mAlignment == 1); // No multi-page allocations
ASSERT(numBytes <= (mPageSize - mPageHeaderSkip)); // // Do the allocation, most likely case inline first, for efficiency. // if (numBytes <= mPageSize - mCurrentPageOffset)
{ // // Safe to allocate from mCurrentPageOffset. //
uint8_t *memory = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset;
mCurrentPageOffset += numBytes; return memory;
} return allocateNewPage(numBytes); #endif
}
// There is no deallocate. The point of this class is that deallocation can be skipped by the // user of it, as the model of use is to simultaneously deallocate everything at once by calling // pop(), and to not have to solve memory leak problems.
// Catch unwanted allocations. // TODO(jmadill): Remove this when we remove the global allocator. void lock(); void unlock();
private:
size_t mAlignment; // all returned allocations will be aligned at // this granularity, which will be a power of 2 #if !defined(ANGLE_DISABLE_POOL_ALLOC) struct AllocState
{
size_t offset;
PageHeader *page;
}; using AllocStack = std::vector<AllocState>;
// Slow path of allocation when we have to get a new page.
uint8_t *allocateNewPage(size_t numBytes); // Track allocations if and only if we're using guard blocks void *initializeAllocation(uint8_t *memory, size_t numBytes);
// Granularity of allocation from the OS
size_t mPageSize; // Amount of memory to skip to make room for the page header (which is the size of the page // header, or PageHeader in PoolAlloc.cpp)
size_t mPageHeaderSkip; // Next offset in top of inUseList to allocate from. This offset is not necessarily aligned to // anything. When an allocation is made, the data is aligned to mAlignment, and the header (if // any) will align to pointer size by extension (since mAlignment is made aligned to at least // pointer size).
size_t mCurrentPageOffset; // List of popped memory
PageHeader *mFreeList; // List of all memory currently being used. The head of this list is where allocations are // currently being made from.
PageHeader *mInUseList; // Stack of where to allocate from, to partition pool
AllocStack mStack;
int mNumCalls; // just an interesting statistic
size_t mTotalBytes; // just an interesting statistic
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.