// We found allocating strictly doubling amounts of memory from the heap left too // much unused slop, particularly on Android. Instead we'll follow a Fibonacci-like // progression.
// SkFibonacci47 is the first 47 Fibonacci numbers. Fib(47) is the largest value less than 2 ^ 32. extern std::array<const uint32_t, 47> SkFibonacci47; template<uint32_t kMaxSize> class SkFibBlockSizes { public: // staticBlockSize, and firstAllocationSize are parameters describing the initial memory // layout. staticBlockSize describes the size of the inlined memory, and firstAllocationSize // describes the size of the first block to be allocated if the static block is exhausted. By // convention, firstAllocationSize is the first choice for the block unit size followed by // staticBlockSize followed by the default of 1024 bytes.
SkFibBlockSizes(uint32_t staticBlockSize, uint32_t firstAllocationSize) : fIndex{0} {
fBlockUnitSize = firstAllocationSize > 0 ? firstAllocationSize :
staticBlockSize > 0 ? staticBlockSize : 1024;
// SkArenaAlloc allocates object and destroys the allocated objects when destroyed. It's designed // to minimize the number of underlying block allocations. SkArenaAlloc allocates first out of an // (optional) user-provided block of memory, and when that's exhausted it allocates on the heap, // starting with an allocation of firstHeapAllocation bytes. If your data (plus a small overhead) // fits in the user-provided block, SkArenaAlloc never uses the heap, and if it fits in // firstHeapAllocation bytes, it'll use the heap only once. If 0 is specified for // firstHeapAllocation, then blockSize is used unless that too is 0, then 1024 is used. // // Examples: // // char block[mostCasesSize]; // SkArenaAlloc arena(block, mostCasesSize); // // If mostCasesSize is too large for the stack, you can use the following pattern. // // std::unique_ptr<char[]> block{new char[mostCasesSize]}; // SkArenaAlloc arena(block.get(), mostCasesSize, almostAllCasesSize); // // If the program only sometimes allocates memory, use the following pattern. // // SkArenaAlloc arena(nullptr, 0, almostAllCasesSize); // // The storage does not necessarily need to be on the stack. Embedding the storage in a class also // works. // // class Foo { // char storage[mostCasesSize]; // SkArenaAlloc arena (storage, mostCasesSize); // }; // // In addition, the system is optimized to handle POD data including arrays of PODs (where // POD is really data with no destructors). For POD data it has zero overhead per item, and a // typical per block overhead of 8 bytes. For non-POD objects there is a per item overhead of 4 // bytes. For arrays of non-POD objects there is a per array overhead of typically 8 bytes. There // is an addition overhead when switching from POD data to non-POD data of typically 8 bytes. // // If additional blocks are needed they are increased exponentially. This strategy bounds the // recursion of the RunDtorsOnBlock to be limited to O(log size-of-memory). Block size grow using // the Fibonacci sequence which means that for 2^32 memory there are 48 allocations, and for 2^48 // there are 71 allocations. class SkArenaAlloc { public:
SkArenaAlloc(char* block, size_t blockSize, size_t firstHeapAllocation);
template <typename T>
T* make() { if constexpr (std::is_standard_layout<T>::value && std::is_trivial<T>::value) { // Just allocate some aligned bytes. This generates smaller code. return (T*)this->makeBytesAlignedTo(sizeof(T), alignof(T));
} else { // This isn't a POD type, so construct the object properly. return this->make([&](void* objStart) { returnnew(objStart) T();
});
}
}
template <typename T>
T* makeArrayDefault(size_t count) {
T* array = this->allocUninitializedArray<T>(count); for (size_t i = 0; i < count; i++) { // Default initialization: if T is primitive then the value is left uninitialized. new (&array[i]) T;
} return array;
}
template <typename T>
T* makeArray(size_t count) {
T* array = this->allocUninitializedArray<T>(count); for (size_t i = 0; i < count; i++) { // Value initialization: if T is primitive then the value is zero-initialized. new (&array[i]) T();
} return array;
}
template <typename T, typename Initializer>
T* makeInitializedArray(size_t count, Initializer initializer) {
T* array = this->allocUninitializedArray<T>(count); for (size_t i = 0; i < count; i++) { new (&array[i]) T(initializer(i));
} return array;
}
template <typename T>
T* makeArrayCopy(SkSpan<const T> toCopy) {
T* array = this->allocUninitializedArray<T>(toCopy.size()); if constexpr (std::is_trivially_copyable<T>::value) {
memcpy(array, toCopy.data(), toCopy.size_bytes());
} else { for (size_t i = 0; i < toCopy.size(); ++i) { new (&array[i]) T(toCopy[i]);
}
} return array;
}
// Only use makeBytesAlignedTo if none of the typed variants are practical to use. void* makeBytesAlignedTo(size_t size, size_t align) {
AssertRelease(SkTFitsIn<uint32_t>(size)); auto objStart = this->allocObject(SkToU32(size), SkToU32(align));
fCursor = objStart + size;
sk_asan_unpoison_memory_region(objStart, size); return objStart;
}
// Helper for defining allocators with inline/reserved storage. // For argument declarations, stick to the base type (SkArenaAlloc). // Note: Inheriting from the storage first means the storage will outlive the // SkArenaAlloc, letting ~SkArenaAlloc read it as it calls destructors. // (This is mostly only relevant for strict tools like MSAN.) template <size_t InlineStorageSize> class SkSTArenaAlloc : private std::array<char, InlineStorageSize>, public SkArenaAlloc { public: explicit SkSTArenaAlloc(size_t firstHeapAllocation = InlineStorageSize)
: SkArenaAlloc{this->data(), this->size(), firstHeapAllocation} {}
~SkSTArenaAlloc() { // Be sure to unpoison the memory that is probably on the stack.
sk_asan_unpoison_memory_region(this->data(), this->size());
}
};
~SkSTArenaAllocWithReset() { // Be sure to unpoison the memory that is probably on the stack.
sk_asan_unpoison_memory_region(this->data(), this->size());
}
};
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.