LinearAllocator.h revision e537330ead4111cae74668bbc25a332e186d6c91
1/* 2 * Copyright 2012, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef ANDROID_LINEARALLOCATOR_H 27#define ANDROID_LINEARALLOCATOR_H 28 29#include <stddef.h> 30#include <type_traits> 31 32#include <vector> 33 34namespace android { 35namespace uirenderer { 36 37/** 38 * A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids 39 * the overhead of malloc when many objects are allocated. It is most useful when creating many 40 * small objects with a similar lifetime, and doesn't add significant overhead for large 41 * allocations. 42 */ 43class LinearAllocator { 44public: 45 LinearAllocator(); 46 ~LinearAllocator(); 47 48 /** 49 * Reserves and returns a region of memory of at least size 'size', aligning as needed. 50 * Typically this is used in an object's overridden new() method or as a replacement for malloc. 51 * 52 * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling 53 * delete() on an object stored in a buffer is needed, it should be overridden to use 54 * rewindIfLastAlloc() 55 */ 56 void* alloc(size_t size); 57 58 /** 59 * Allocates an instance of the template type with the given construction parameters 60 * and adds it to the automatic destruction list. 61 */ 62 template<class T, typename... Params> 63 T* create(Params... params) { 64 T* ret = new (*this) T(params...); 65 autoDestroy(ret); 66 return ret; 67 } 68 69 /** 70 * Adds the pointer to the tracking list to have its destructor called 71 * when the LinearAllocator is destroyed. 72 */ 73 template<class T> 74 void autoDestroy(T* addr) { 75 if (!std::is_trivially_destructible<T>::value) { 76 auto dtor = [](void* addr) { ((T*)addr)->~T(); }; 77 addToDestructionList(dtor, addr); 78 } 79 } 80 81 /** 82 * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its 83 * state if possible. 84 */ 85 void rewindIfLastAlloc(void* ptr, size_t allocSize); 86 87 /** 88 * Same as rewindIfLastAlloc(void*, size_t) 89 */ 90 template<class T> 91 void rewindIfLastAlloc(T* ptr) { 92 rewindIfLastAlloc((void*)ptr, sizeof(T)); 93 } 94 95 /** 96 * Dump memory usage statistics to the log (allocated and wasted space) 97 */ 98 void dumpMemoryStats(const char* prefix = ""); 99 100 /** 101 * The number of bytes used for buffers allocated in the LinearAllocator (does not count space 102 * wasted) 103 */ 104 size_t usedSize() const { return mTotalAllocated - mWastedSpace; } 105 106private: 107 LinearAllocator(const LinearAllocator& other); 108 109 class Page; 110 typedef void (*Destructor)(void* addr); 111 struct DestructorNode { 112 Destructor dtor; 113 void* addr; 114 DestructorNode* next = nullptr; 115 }; 116 117 void addToDestructionList(Destructor, void* addr); 118 void runDestructorFor(void* addr); 119 Page* newPage(size_t pageSize); 120 bool fitsInCurrentPage(size_t size); 121 void ensureNext(size_t size); 122 void* start(Page *p); 123 void* end(Page* p); 124 125 size_t mPageSize; 126 size_t mMaxAllocSize; 127 void* mNext; 128 Page* mCurrentPage; 129 Page* mPages; 130 DestructorNode* mDtorList = nullptr; 131 132 // Memory usage tracking 133 size_t mTotalAllocated; 134 size_t mWastedSpace; 135 size_t mPageCount; 136 size_t mDedicatedPageCount; 137}; 138 139template <class T> 140class LinearStdAllocator { 141public: 142 typedef T value_type; // needed to implement std::allocator 143 typedef T* pointer; // needed to implement std::allocator 144 145 LinearStdAllocator(LinearAllocator& allocator) 146 : linearAllocator(allocator) {} 147 LinearStdAllocator(const LinearStdAllocator& other) 148 : linearAllocator(other.linearAllocator) {} 149 ~LinearStdAllocator() {} 150 151 // rebind marks that allocators can be rebound to different types 152 template <class U> 153 struct rebind { 154 typedef LinearStdAllocator<U> other; 155 }; 156 // enable allocators to be constructed from other templated types 157 template <class U> 158 LinearStdAllocator(const LinearStdAllocator<U>& other) 159 : linearAllocator(other.linearAllocator) {} 160 161 T* allocate(size_t num, const void* = 0) { 162 return (T*)(linearAllocator.alloc(num * sizeof(T))); 163 } 164 165 void deallocate(pointer p, size_t num) { 166 // attempt to rewind, but no guarantees 167 linearAllocator.rewindIfLastAlloc(p, num * sizeof(T)); 168 } 169 170 // public so template copy constructor can access 171 LinearAllocator& linearAllocator; 172}; 173 174// return that all specializations of LinearStdAllocator are interchangeable 175template <class T1, class T2> 176bool operator== (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return true; } 177template <class T1, class T2> 178bool operator!= (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return false; } 179 180template <class T> 181class LsaVector : public std::vector<T, LinearStdAllocator<T>> { 182public: 183 LsaVector(const LinearStdAllocator<T>& allocator) 184 : std::vector<T, LinearStdAllocator<T>>(allocator) {} 185}; 186 187}; // namespace uirenderer 188}; // namespace android 189 190void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la); 191 192#endif // ANDROID_LINEARALLOCATOR_H 193