2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
13 \defgroup MemPoolsAPI Memory Management (Memory Pool Allocator)
17 * MemPools are a pooled memory allocator running on top of malloc(). It's
18 * purpose is to reduce memory fragmentation and provide detailed statistics
19 * on memory consumption.
22 * Preferably all memory allocations in Squid should be done using MemPools
23 * or one of the types built on top of it (i.e. cbdata).
25 \note Usually it is better to use cbdata types as these gives you additional
26 * safeguards in references and typechecking. However, for high usage pools where
27 * the cbdata functionality of cbdata is not required directly using a MemPool
28 * might be the way to go.
31 #include "mem/Meter.h"
35 #include <gnumalloc.h>
49 /// \ingroup MemPoolsAPI
50 #define toMB(size) ( ((double) size) / ((double)(1024*1024)) )
51 /// \ingroup MemPoolsAPI
52 #define toKB(size) ( (size + 1024 - 1) / 1024 )
54 /// \ingroup MemPoolsAPI
55 #define MEM_PAGE_SIZE 4096
56 /// \ingroup MemPoolsAPI
57 #define MEM_MIN_FREE 32
58 /// \ingroup MemPoolsAPI
59 #define MEM_MAX_FREE 65535 /* unsigned short is max number of items per chunk */
61 class MemImplementingAllocator
;
64 /// \ingroup MemPoolsAPI
65 /// TODO: Kill this typedef for C++
66 typedef struct _MemPoolGlobalStats MemPoolGlobalStats
;
68 /// \ingroup MemPoolsAPI
72 MemImplementingAllocator
*pool
;
73 MemPoolIterator
* next
;
78 * Object to track per-pool cumulative counters
83 mgb_t() : count(0), bytes(0) {}
90 * Object to track per-pool memory usage (alloc = inuse+idle)
102 /** history Allocations */
106 /** account Saved Allocations */
109 /** account Free calls */
113 class MemImplementingAllocator
;
115 /// \ingroup MemPoolsAPI
119 static MemPools
&GetInstance();
124 \param label Name for the pool. Displayed in stats.
125 \param obj_size Size of elements in MemPool.
127 MemImplementingAllocator
* create(const char *label
, size_t obj_size
);
130 * Sets upper limit in bytes to amount of free ram kept in pools. This is
131 * not strict upper limit, but a hint. When MemPools are over this limit,
132 * totally free chunks are immediately considered for release. Otherwise
133 * only chunks that have not been referenced for a long time are checked.
135 void setIdleLimit(ssize_t new_idle_limit
);
136 ssize_t
idleLimit() const;
140 * Main cleanup handler. For MemPools to stay within upper idle limits,
141 * this function needs to be called periodically, preferably at some
142 * constant rate, eg. from Squid event. It looks through all pools and
143 * chunks, cleans up internal states and checks for releasable chunks.
146 * Between the calls to this function objects are placed onto internal
147 * cache instead of returning to their home chunks, mainly for speedup
148 * purpose. During that time state of chunk is not known, it is not
149 * known whether chunk is free or in use. This call returns all objects
150 * to their chunks and restores consistency.
153 * Should be called relatively often, as it sorts chunks in suitable
154 * order as to reduce free memory fragmentation and increase chunk
156 * Suitable frequency for cleanup is in range of few tens of seconds to
157 * few minutes, depending of memory activity.
159 * TODO: DOCS: Re-write this shorter!
161 \param maxage Release all totally idle chunks that
162 * have not been referenced for maxage seconds.
164 void clean(time_t maxage
);
166 void setDefaultPoolChunking(bool const &);
168 MemImplementingAllocator
*pools
= nullptr;
169 ssize_t mem_idle_limit
= (2 << 20) /* 2MB */;
171 bool defaultIsChunked
= false;
176 * a pool is a [growing] space for objects of the same size
181 MemAllocator (char const *aLabel
);
182 virtual ~MemAllocator() {}
185 \param stats Object to be filled with statistical data about pool.
186 \retval Number of objects in use, ie. allocated.
188 virtual int getStats(MemPoolStats
* stats
, int accumulate
= 0) = 0;
190 virtual MemPoolMeter
const &getMeter() const = 0;
193 * Allocate one element from the pool
195 virtual void *alloc() = 0;
198 * Free a element allocated by MemAllocator::alloc()
200 virtual void freeOne(void *) = 0;
202 virtual char const *objectType() const;
203 virtual size_t objectSize() const = 0;
204 virtual int getInUseCount() = 0;
205 void zeroBlocks(bool doIt
) {doZero
= doIt
;}
209 * Allows you tune chunk size of pooling. Objects are allocated in chunks
210 * instead of individually. This conserves memory, reduces fragmentation.
211 * Because of that memory can be freed also only in chunks. Therefore
212 * there is tradeoff between memory conservation due to chunking and free
213 * memory fragmentation.
215 \note As a general guideline, increase chunk size only for pools that keep
216 * very many items for relatively long time.
218 virtual void setChunkSize(size_t) {}
221 \param minSize Minimum size needed to be allocated.
222 \retval n Smallest size divisible by sizeof(void*)
224 static size_t RoundedSize(size_t minSize
);
227 /** Whether to zero memory on initial allocation and on return to the pool.
229 * We do this on some pools because many object constructors are/were incomplete
230 * and we are afraid some code may use the object after free.
231 * These probems are becoming less common, so when possible set this to false.
239 /// \ingroup MemPoolsAPI
240 class MemImplementingAllocator
: public MemAllocator
243 MemImplementingAllocator(char const *aLabel
, size_t aSize
);
244 virtual ~MemImplementingAllocator();
245 virtual MemPoolMeter
const &getMeter() const;
246 virtual MemPoolMeter
&getMeter();
247 virtual void flushMetersFull();
248 virtual void flushMeters();
251 * Allocate one element from the pool
253 virtual void *alloc();
256 * Free a element allocated by MemImplementingAllocator::alloc()
258 virtual void freeOne(void *);
260 virtual bool idleTrigger(int shift
) const = 0;
261 virtual void clean(time_t maxage
) = 0;
262 virtual size_t objectSize() const;
263 virtual int getInUseCount() = 0;
265 virtual void *allocate() = 0;
266 virtual void deallocate(void *, bool aggressive
) = 0;
270 MemImplementingAllocator
*next
;
278 /// \ingroup MemPoolsAPI
301 /// \ingroup MemPoolsAPI
302 /// TODO: Classify and add constructor/destructor to initialize properly.
303 struct _MemPoolGlobalStats
{
304 MemPoolMeter
*TheMeter
;
308 int tot_pools_mempid
;
310 int tot_chunks_alloc
;
311 int tot_chunks_inuse
;
312 int tot_chunks_partial
;
320 ssize_t mem_idle_limit
;
323 /// \ingroup MemPoolsAPI
324 /// Creates a named MemPool of elements with the given size
325 #define memPoolCreate MemPools::GetInstance().create
330 * Initialise iteration through all of the pools.
331 * \returns Iterator for use by memPoolIterateNext() and memPoolIterateDone()
333 extern MemPoolIterator
* memPoolIterate(void);
337 * Get next pool pointer, until getting NULL pointer.
339 extern MemImplementingAllocator
* memPoolIterateNext(MemPoolIterator
* iter
);
343 * Should be called after finished with iterating through all pools.
345 extern void memPoolIterateDone(MemPoolIterator
** iter
);
350 * Fills a MemPoolGlobalStats with statistical data about overall
351 * usage for all pools.
353 * \param stats Object to be filled with statistical data.
355 * \return Number of pools that have at least one object in use.
356 * Ie. number of dirty pools.
358 extern int memPoolGetGlobalStats(MemPoolGlobalStats
* stats
);
360 /// \ingroup MemPoolsAPI
361 extern int memPoolsTotalAllocated(void);
363 #endif /* _MEM_POOL_H_ */