objSizeAndOverhead += alignment - 1;
}
- uint32_t allocationSize = std::max(objSizeAndOverhead, fExtraSize << fLogGrowth);
- fLogGrowth++;
+ uint32_t allocationSize = std::max(objSizeAndOverhead, fExtraSize * fFib0);
+ fFib0 += fFib1;
+ std::swap(fFib0, fFib1);
// Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K
// heuristic is from the JEMalloc behavior.
// 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(ln size-of-memory). In practical terms, this
-// is a maximum recursion depth of 33 for an 8GB machine but usually much less.
+// 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 size, size_t extraSize = 0);
char* const fFirstBlock;
const uint32_t fFirstSize;
const uint32_t fExtraSize;
- // The extra size allocations grow exponentially:
- // size-allocated = extraSize * 2 ^ fLogGrowth.
- uint8_t fLogGrowth {0};
+ // Use the Fibonacci sequence as the growth factor for block size. The size of the block
+ // allocated is fFib0 * fExtraSize. Using 2 ^ n * fExtraSize had too much slop for Android.
+ uint32_t fFib0 {1}, fFib1 {1};
};
#endif//SkFixedAlloc_DEFINED