2 * mempool.c: efficient memory allocation
4 * MonoMemPool is for fast allocation of memory. We free
5 * all memory when the pool is destroyed.
8 * Dietmar Maurer (dietmar@ximian.com)
10 * (C) 2001 Ximian, Inc.
20 * MonoMemPool is for fast allocation of memory. We free
21 * all memory when the pool is destroyed.
26 #define MONO_MEMPOOL_PAGESIZE 8192
27 #define MONO_MEMPOOL_MINSIZE 512
30 #define G_LIKELY(a) (a)
31 #define G_UNLIKELY(a) (a)
40 double pad; /* to assure proper alignment */
48 * Returns: a new memory pool.
51 mono_mempool_new (void)
53 return mono_mempool_new_size (MONO_MEMPOOL_PAGESIZE);
57 mono_mempool_new_size (int initial_size)
60 if (initial_size < MONO_MEMPOOL_MINSIZE)
61 initial_size = MONO_MEMPOOL_MINSIZE;
62 pool = g_malloc (initial_size);
65 pool->pos = (guint8*)pool + sizeof (MonoMemPool);
66 pool->end = pool->pos + initial_size - sizeof (MonoMemPool);
67 pool->d.allocated = pool->size = initial_size;
72 * mono_mempool_destroy:
73 * @pool: the memory pool to destroy
75 * Free all memory associated with this pool.
78 mono_mempool_destroy (MonoMemPool *pool)
91 * mono_mempool_invalidate:
92 * @pool: the memory pool to invalidate
94 * Fill the memory associated with this pool to 0x2a (42). Useful for debugging.
97 mono_mempool_invalidate (MonoMemPool *pool)
104 memset (p, 42, p->size);
110 mono_mempool_empty (MonoMemPool *pool)
112 pool->pos = (guint8*)pool + sizeof (MonoMemPool);
113 pool->end = pool->pos + pool->size - sizeof (MonoMemPool);
117 * mono_mempool_stats:
118 * @pool: the momory pool we need stats for
120 * Print a few stats about the mempool
123 mono_mempool_stats (MonoMemPool *pool)
127 guint32 still_free = 0;
131 still_free += p->end - p->pos;
136 g_print ("Mempool %p stats:\n", pool);
137 g_print ("Total mem allocated: %d\n", pool->d.allocated);
138 g_print ("Num chunks: %d\n", count);
139 g_print ("Free memory: %d\n", still_free);
143 #ifdef TRACE_ALLOCATIONS
144 #include <execinfo.h>
145 #include "metadata/appdomain.h"
146 #include "metadata/metadata-internals.h"
149 mono_backtrace (int limit)
154 backtrace (array, limit);
155 names = backtrace_symbols (array, limit);
156 for (i = 1; i < limit; ++i) {
157 g_print ("\t%s\n", names [i]);
165 get_next_size (MonoMemPool *pool, int size)
167 int target = pool->next? pool->next->size: pool->size;
168 size += sizeof (MonoMemPool);
169 /* increase the size */
170 target += target / 2;
171 while (target < size) {
172 target += target / 2;
174 if (target > MONO_MEMPOOL_PAGESIZE)
175 target = MONO_MEMPOOL_PAGESIZE;
176 /* we are called with size smaller than 4096 */
177 g_assert (size <= MONO_MEMPOOL_PAGESIZE);
182 * mono_mempool_alloc:
183 * @pool: the momory pool to destroy
184 * @size: size of the momory block
186 * Allocates a new block of memory in @pool.
188 * Returns: the address of a newly allocated memory block.
191 mono_mempool_alloc (MonoMemPool *pool, guint size)
195 size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
198 pool->pos = (guint8*)rval + size;
200 #ifdef TRACE_ALLOCATIONS
201 if (pool == mono_get_corlib ()->mempool) {
202 g_print ("Allocating %d bytes\n", size);
206 if (G_UNLIKELY (pool->pos >= pool->end)) {
209 MonoMemPool *np = g_malloc (sizeof (MonoMemPool) + size);
210 np->next = pool->next;
212 np->pos = (guint8*)np + sizeof (MonoMemPool);
213 np->size = sizeof (MonoMemPool) + size;
214 np->end = np->pos + np->size - sizeof (MonoMemPool);
215 pool->d.allocated += sizeof (MonoMemPool) + size;
216 return (guint8*)np + sizeof (MonoMemPool);
218 int new_size = get_next_size (pool, size);
219 MonoMemPool *np = g_malloc (new_size);
220 np->next = pool->next;
222 pool->pos = (guint8*)np + sizeof (MonoMemPool);
223 np->pos = (guint8*)np + sizeof (MonoMemPool);
226 pool->end = pool->pos + new_size - sizeof (MonoMemPool);
227 pool->d.allocated += new_size;
238 * mono_mempool_alloc0:
240 * same as mono_mempool_alloc, but fills memory with zero.
243 mono_mempool_alloc0 (MonoMemPool *pool, guint size)
247 size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
250 pool->pos = (guint8*)rval + size;
252 if (G_UNLIKELY (pool->pos >= pool->end)) {
253 rval = mono_mempool_alloc (pool, size);
256 memset (rval, 0, size);
261 * mono_mempool_contains_addr:
263 * Determines whenever ADDR is inside the memory used by the mempool.
266 mono_mempool_contains_addr (MonoMemPool *pool,
273 if (addr > (gpointer)p && addr <= (gpointer)((guint8*)p + p->size))
282 * mono_mempool_strdup:
284 * Same as strdup, but allocates memory from the mempool.
285 * Returns: a pointer to the newly allocated string data inside the mempool.
288 mono_mempool_strdup (MonoMemPool *pool,
298 res = mono_mempool_alloc (pool, l + 1);
299 memcpy (res, s, l + 1);
305 * mono_mempool_get_allocated:
307 * Return the amount of memory allocated for this mempool.
310 mono_mempool_get_allocated (MonoMemPool *pool)
312 return pool->d.allocated;