OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef GrMemoryPool_DEFINED | 8 #ifndef GrMemoryPool_DEFINED |
9 #define GrMemoryPool_DEFINED | 9 #define GrMemoryPool_DEFINED |
10 | 10 |
11 #include "GrTypes.h" | 11 #include "GrTypes.h" |
12 | 12 |
13 /** | 13 /** |
14 * Allocates memory in blocks and parcels out space in the blocks for allocation | 14 * Allocates memory in blocks and parcels out space in the blocks for allocation |
15 * requests. It is optimized for allocate / release speed over memory | 15 * requests. It is optimized for allocate / release speed over memory |
16 * effeciency. The interface is designed to be used to implement operator new | 16 * efficiency. The interface is designed to be used to implement operator new |
17 * and delete overrides. All allocations are expected to be released before the | 17 * and delete overrides. All allocations are expected to be released before the |
18 * pool's destructor is called. Allocations will be 8-byte aligned. | 18 * pool's destructor is called. Allocations will be 8-byte aligned. |
19 */ | 19 */ |
20 class GrMemoryPool { | 20 class GrMemoryPool { |
21 public: | 21 public: |
22 /** | 22 /** |
23 * Prealloc size is the amount of space to make available at pool creation | 23 * Prealloc size is the amount of space to allocate at pool creation |
24 * time and keep around until pool destruction. The min alloc size is the | 24 * time and keep around until pool destruction. The min alloc size is |
25 * smallest allowed size of additional allocations. | 25 * the smallest allowed size of additional allocations. Both sizes are |
26 * adjusted to ensure that: | |
27 * 1. they are are 8-byte aligned | |
herb_g
2016/11/29 18:31:14
Generally , 8-byte alignment is not enough. You sh
| |
28 * 2. minAllocSize >= kSmallestMinAllocSize | |
29 * 3. preallocSize >= minAllocSize | |
30 * | |
31 * Both sizes is what the pool will end up allocating from the system, and | |
32 * portions of the allocated memory is used for internal bookkeeping. | |
26 */ | 33 */ |
27 GrMemoryPool(size_t preallocSize, size_t minAllocSize); | 34 GrMemoryPool(size_t preallocSize, size_t minAllocSize); |
28 | 35 |
29 ~GrMemoryPool(); | 36 ~GrMemoryPool(); |
30 | 37 |
31 /** | 38 /** |
32 * Allocates memory. The memory must be freed with release(). | 39 * Allocates memory. The memory must be freed with release(). |
33 */ | 40 */ |
34 void* allocate(size_t size); | 41 void* allocate(size_t size); |
35 | 42 |
36 /** | 43 /** |
37 * p must have been returned by allocate() | 44 * p must have been returned by allocate() |
38 */ | 45 */ |
39 void release(void* p); | 46 void release(void* p); |
40 | 47 |
41 /** | 48 /** |
42 * Returns true if there are no unreleased allocations. | 49 * Returns true if there are no unreleased allocations. |
43 */ | 50 */ |
44 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; } | 51 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; } |
45 | 52 |
46 /** | 53 /** |
47 * Returns the total allocated size of the GrMemoryPool minus any preallocat ed amount | 54 * Returns the total allocated size of the GrMemoryPool minus any preallocat ed amount |
48 */ | 55 */ |
49 size_t size() const { return fSize; } | 56 size_t size() const { return fSize; } |
50 | 57 |
58 /** | |
59 * Returns the preallocated size of the GrMemoryPool | |
60 */ | |
61 size_t preallocSize() const { return fHead->fSize; } | |
62 | |
63 /** | |
64 * Minimum value of minAllocSize constructor argument. | |
65 */ | |
66 constexpr static size_t kSmallestMinAllocSize = 1 << 10; | |
67 | |
51 private: | 68 private: |
52 struct BlockHeader; | 69 struct BlockHeader; |
53 | 70 |
54 static BlockHeader* CreateBlock(size_t size); | 71 static BlockHeader* CreateBlock(size_t size); |
55 | 72 |
56 static void DeleteBlock(BlockHeader* block); | 73 static void DeleteBlock(BlockHeader* block); |
57 | 74 |
58 void validate(); | 75 void validate(); |
59 | 76 |
60 struct BlockHeader { | 77 struct BlockHeader { |
(...skipping 13 matching lines...) Expand all Loading... | |
74 static const uint32_t kAssignedMarker = 0xCDCDCDCD; | 91 static const uint32_t kAssignedMarker = 0xCDCDCDCD; |
75 static const uint32_t kFreedMarker = 0xEFEFEFEF; | 92 static const uint32_t kFreedMarker = 0xEFEFEFEF; |
76 | 93 |
77 struct AllocHeader { | 94 struct AllocHeader { |
78 #ifdef SK_DEBUG | 95 #ifdef SK_DEBUG |
79 uint32_t fSentinal; ///< known value to check for memory stomping ( e.g., (CD)*) | 96 uint32_t fSentinal; ///< known value to check for memory stomping ( e.g., (CD)*) |
80 #endif | 97 #endif |
81 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides | 98 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides |
82 }; | 99 }; |
83 | 100 |
84 enum { | |
85 // We assume this alignment is good enough for everybody. | |
86 kAlignment = 8, | |
87 kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), | |
88 kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), | |
89 }; | |
90 size_t fSize; | 101 size_t fSize; |
91 size_t fPreallocSize; | |
92 size_t fMinAllocSize; | 102 size_t fMinAllocSize; |
93 BlockHeader* fHead; | 103 BlockHeader* fHead; |
94 BlockHeader* fTail; | 104 BlockHeader* fTail; |
95 #ifdef SK_DEBUG | 105 #ifdef SK_DEBUG |
96 int fAllocationCnt; | 106 int fAllocationCnt; |
97 int fAllocBlockCnt; | 107 int fAllocBlockCnt; |
98 #endif | 108 #endif |
109 | |
110 protected: | |
111 enum { | |
112 // We assume this alignment is good enough for everybody. | |
113 kAlignment = 8, | |
114 kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), | |
115 kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), | |
116 }; | |
99 }; | 117 }; |
100 | 118 |
119 /** | |
120 * Variant of GrMemoryPool that can only allocate objects of a single type. It i s | |
121 * not as flexible as GrMemoryPool, but it has more convenient allocate() method , | |
122 * and more importantly, it guarantees number of objects that are preallocated a t | |
123 * construction or when adding a new memory block. I.e. | |
124 * | |
125 * GrMemoryPool pool(3 * sizeof(T), 1000 * sizeof(T)); | |
126 * pool.allocate(sizeof(T)); | |
127 * pool.allocate(sizeof(T)); | |
128 * pool.allocate(sizeof(T)); | |
129 * | |
130 * will preallocate 3 * sizeof(T) bytes and use some of those bytes for internal | |
131 * structures. Because of that, last allocate() call will end up allocating a ne w | |
132 * block of 1000 * sizeof(T) bytes. In contrast, | |
133 * | |
134 * GrObjectMemoryPool<T> pool(3, 1000); | |
135 * pool.allocate(); | |
136 * pool.allocate(); | |
137 * pool.allocate(); | |
138 * | |
139 * guarantees to preallocate enough memory for 3 objects of sizeof(T), so last | |
140 * allocate() will use preallocated memory and won't cause allocation of a new b lock. | |
141 * | |
142 * Same thing is true for the second (minAlloc) ctor argument: this class guaran tees | |
143 * that a newly added block will have enough space for 1000 objects of sizeof(T) , while | |
144 * GrMemoryPool does not. | |
145 */ | |
146 template <class T> | |
147 class GrObjectMemoryPool: public GrMemoryPool { | |
148 public: | |
149 /** | |
150 * Preallocates memory for preallocCount objects, and sets new block size to be | |
151 * enough to hold minAllocCount objects. | |
152 */ | |
153 GrObjectMemoryPool(size_t preallocCount, size_t minAllocCount) | |
154 : GrMemoryPool(CountToSize(preallocCount), | |
155 CountToSize(SkTMax(minAllocCount, kSmallestMinAllocCount) )) { | |
156 } | |
157 | |
158 /** | |
159 * Allocates memory for an object, but doesn't construct or otherwise initia lize it. | |
160 * The memory must be freed with release(). | |
161 */ | |
162 T* allocate() { return static_cast<T*>(GrMemoryPool::allocate(sizeof(T))); } | |
herb_g
2016/11/29 18:31:14
I think this is a very dangerous API. It is not RA
| |
163 | |
164 private: | |
165 constexpr static size_t kTotalObjectSize = | |
166 kPerAllocPad + GR_CT_ALIGN_UP(sizeof(T), kAlignment); | |
167 | |
168 constexpr static size_t CountToSize(size_t count) { | |
169 return kHeaderSize + count * kTotalObjectSize; | |
170 } | |
171 | |
172 public: | |
173 /** | |
174 * Minimum value of minAllocCount constructor argument. | |
175 */ | |
176 constexpr static size_t kSmallestMinAllocCount = | |
177 (GrMemoryPool::kSmallestMinAllocSize - kHeaderSize + kTotalObjectSize - 1) / | |
178 kTotalObjectSize; | |
179 }; | |
180 | |
181 template <class T> | |
182 constexpr size_t GrObjectMemoryPool<T>::kSmallestMinAllocCount; | |
183 | |
101 #endif | 184 #endif |
OLD | NEW |