1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GLib Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GLib at ftp://ftp.gtk.org/pub/gtk/.
38 #include "gthreadprivate.h"
41 #define MEM_PROFILE_TABLE_SIZE 4096
45 * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and
47 * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works.
48 * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions
49 * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here.
50 * g_mem_gc_friendly is TRUE, freed memory should be 0-wiped.
53 /* --- prototypes --- */
54 static gboolean g_mem_initialized = FALSE;
55 static void g_mem_init_nomessage (void);
58 /* --- malloc wrappers --- */
59 #ifndef REALLOC_0_WORKS
61 standard_realloc (gpointer mem,
65 return malloc (n_bytes);
67 return realloc (mem, n_bytes);
69 #endif /* !REALLOC_0_WORKS */
71 #ifdef SANE_MALLOC_PROTOS
72 # define standard_malloc malloc
73 # ifdef REALLOC_0_WORKS
74 # define standard_realloc realloc
75 # endif /* REALLOC_0_WORKS */
76 # define standard_free free
77 # define standard_calloc calloc
78 # define standard_try_malloc malloc
79 # define standard_try_realloc realloc
80 #else /* !SANE_MALLOC_PROTOS */
82 standard_malloc (gsize n_bytes)
84 return malloc (n_bytes);
86 # ifdef REALLOC_0_WORKS
88 standard_realloc (gpointer mem,
91 return realloc (mem, n_bytes);
93 # endif /* REALLOC_0_WORKS */
95 standard_free (gpointer mem)
100 standard_calloc (gsize n_blocks,
103 return calloc (n_blocks, n_bytes);
105 #define standard_try_malloc standard_malloc
106 #define standard_try_realloc standard_realloc
107 #endif /* !SANE_MALLOC_PROTOS */
110 /* --- variables --- */
111 static GMemVTable glib_mem_vtable = {
117 standard_try_realloc,
121 /* --- functions --- */
123 g_malloc (gsize n_bytes)
125 if (G_UNLIKELY (!g_mem_initialized))
126 g_mem_init_nomessage();
127 if (G_LIKELY (n_bytes))
131 mem = glib_mem_vtable.vmalloc (n_bytes);
135 #if NOT_NEEDED_FOR_NAVIT
136 g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
138 #endif /* NOT_NEEDED_FOR_NAVIT */
145 g_malloc0 (gsize n_bytes)
147 if (G_UNLIKELY (!g_mem_initialized))
148 g_mem_init_nomessage();
149 if (G_LIKELY (n_bytes))
153 mem = glib_mem_vtable.vcalloc (1, n_bytes);
157 #if NOT_NEEDED_FOR_NAVIT
158 g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
160 #endif /* NOT_NEEDED_FOR_NAVIT */
167 g_realloc (gpointer mem,
170 if (G_UNLIKELY (!g_mem_initialized))
171 g_mem_init_nomessage();
172 if (G_LIKELY (n_bytes))
174 mem = glib_mem_vtable.vrealloc (mem, n_bytes);
178 #if NOT_NEEDED_FOR_NAVIT
179 g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
181 #endif /* NOT_NEEDED_FOR_NAVIT */
185 glib_mem_vtable.vfree (mem);
191 g_free (gpointer mem)
193 if (G_UNLIKELY (!g_mem_initialized))
194 g_mem_init_nomessage();
196 glib_mem_vtable.vfree (mem);
200 g_try_malloc (gsize n_bytes)
202 if (G_UNLIKELY (!g_mem_initialized))
203 g_mem_init_nomessage();
204 if (G_LIKELY (n_bytes))
205 return glib_mem_vtable.vtry_malloc (n_bytes);
211 g_try_malloc0 (gsize n_bytes)
215 mem = g_try_malloc (n_bytes);
218 memset (mem, 0, n_bytes);
224 g_try_realloc (gpointer mem,
227 if (G_UNLIKELY (!g_mem_initialized))
228 g_mem_init_nomessage();
229 if (G_LIKELY (n_bytes))
230 return glib_mem_vtable.vtry_realloc (mem, n_bytes);
233 glib_mem_vtable.vfree (mem);
239 fallback_calloc (gsize n_blocks,
242 gsize l = n_blocks * n_block_bytes;
243 gpointer mem = glib_mem_vtable.vmalloc (l);
251 static gboolean vtable_set = FALSE;
254 * g_mem_is_system_malloc
256 * Checks whether the allocator used by g_malloc() is the system's
257 * malloc implementation. If it returns %TRUE memory allocated with
258 * malloc() can be used interchangeable with memory allocated using g_malloc().
259 * This function is useful for avoiding an extra copy of allocated memory returned
260 * by a non-GLib-based API.
262 * A different allocator can be set using g_mem_set_vtable().
264 * Return value: if %TRUE, malloc() and g_malloc() can be mixed.
267 g_mem_is_system_malloc (void)
273 g_mem_set_vtable (GMemVTable *vtable)
277 if (vtable->vmalloc && vtable->vrealloc && vtable->vfree)
279 glib_mem_vtable.vmalloc = vtable->vmalloc;
280 glib_mem_vtable.vrealloc = vtable->vrealloc;
281 glib_mem_vtable.vfree = vtable->vfree;
282 glib_mem_vtable.vcalloc = vtable->vcalloc ? vtable->vcalloc : fallback_calloc;
283 glib_mem_vtable.vtry_malloc = vtable->vtry_malloc ? vtable->vtry_malloc : glib_mem_vtable.vmalloc;
284 glib_mem_vtable.vtry_realloc = vtable->vtry_realloc ? vtable->vtry_realloc : glib_mem_vtable.vrealloc;
287 #if NOT_NEEDED_FOR_NAVIT
289 g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()");
290 #endif /* NOT_NEEDED_FOR_NAVIT */
292 #if NOT_NEEDED_FOR_NAVIT
294 g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup");
295 #endif /* NOT_NEEDED_FOR_NAVIT */
299 /* --- memory profiling and checking --- */
300 #ifdef G_DISABLE_CHECKS
301 GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
306 #else /* !G_DISABLE_CHECKS */
313 static guint *profile_data = NULL;
314 static gsize profile_allocs = 0;
315 static gsize profile_zinit = 0;
316 static gsize profile_frees = 0;
317 static GMutex *gmem_profile_mutex = NULL;
318 #ifdef G_ENABLE_DEBUG
319 static volatile gsize g_trap_free_size = 0;
320 static volatile gsize g_trap_realloc_size = 0;
321 static volatile gsize g_trap_malloc_size = 0;
322 #endif /* G_ENABLE_DEBUG */
324 #define PROFILE_TABLE(f1,f2,f3) ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1))
327 profiler_log (ProfilerJob job,
331 g_mutex_lock (gmem_profile_mutex);
334 profile_data = standard_calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8,
335 sizeof (profile_data[0]));
336 if (!profile_data) /* memory system kiddin' me, eh? */
338 g_mutex_unlock (gmem_profile_mutex);
343 if (n_bytes < MEM_PROFILE_TABLE_SIZE)
344 profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
345 (job & PROFILER_RELOC) != 0,
348 profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
349 (job & PROFILER_RELOC) != 0,
353 if (job & PROFILER_ALLOC)
355 profile_allocs += n_bytes;
356 if (job & PROFILER_ZINIT)
357 profile_zinit += n_bytes;
360 profile_frees += n_bytes;
362 g_mutex_unlock (gmem_profile_mutex);
366 profile_print_locked (guint *local_data,
369 gboolean need_header = TRUE;
372 for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++)
374 glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)];
375 glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)];
376 glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)];
377 glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)];
379 if (!t_malloc && !t_realloc && !t_free && !t_refree)
381 else if (need_header)
384 g_print (" blocks of | allocated | freed | allocated | freed | n_bytes \n");
385 g_print (" n_bytes | n_times by | n_times by | n_times by | n_times by | remaining \n");
386 g_print (" | malloc() | free() | realloc() | realloc() | \n");
387 g_print ("===========|============|============|============|============|===========\n");
389 if (i < MEM_PROFILE_TABLE_SIZE)
390 g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n",
391 i, t_malloc, t_free, t_realloc, t_refree,
392 (t_malloc - t_free + t_realloc - t_refree) * i);
393 else if (i >= MEM_PROFILE_TABLE_SIZE)
394 g_print (" >%6u | %10ld | %10ld | %10ld | %10ld | ***\n",
395 i, t_malloc, t_free, t_realloc, t_refree);
398 g_print (" --- none ---\n");
404 guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])];
409 if (G_UNLIKELY (!g_mem_initialized))
410 g_mem_init_nomessage();
412 g_mutex_lock (gmem_profile_mutex);
414 local_allocs = profile_allocs;
415 local_zinit = profile_zinit;
416 local_frees = profile_frees;
420 g_mutex_unlock (gmem_profile_mutex);
424 memcpy (local_data, profile_data,
425 (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0]));
427 g_mutex_unlock (gmem_profile_mutex);
429 g_print ("GLib Memory statistics (successful operations):\n");
430 profile_print_locked (local_data, TRUE);
431 g_print ("GLib Memory statistics (failing operations):\n");
432 profile_print_locked (local_data, FALSE);
433 g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", "
434 "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), "
435 "freed=%"G_GSIZE_FORMAT" (%.2f%%), "
436 "remaining=%"G_GSIZE_FORMAT"\n",
439 ((gdouble) local_zinit) / local_allocs * 100.0,
441 ((gdouble) local_frees) / local_allocs * 100.0,
442 local_allocs - local_frees);
446 profiler_try_malloc (gsize n_bytes)
450 #ifdef G_ENABLE_DEBUG
451 if (g_trap_malloc_size == n_bytes)
453 #endif /* G_ENABLE_DEBUG */
455 p = standard_malloc (sizeof (gsize) * 2 + n_bytes);
459 p[0] = 0; /* free count */
460 p[1] = n_bytes; /* length */
461 profiler_log (PROFILER_ALLOC, n_bytes, TRUE);
465 profiler_log (PROFILER_ALLOC, n_bytes, FALSE);
471 profiler_malloc (gsize n_bytes)
473 gpointer mem = profiler_try_malloc (n_bytes);
482 profiler_calloc (gsize n_blocks,
485 gsize l = n_blocks * n_block_bytes;
488 #ifdef G_ENABLE_DEBUG
489 if (g_trap_malloc_size == l)
491 #endif /* G_ENABLE_DEBUG */
493 p = standard_calloc (1, sizeof (gsize) * 2 + l);
497 p[0] = 0; /* free count */
498 p[1] = l; /* length */
499 profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE);
504 profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE);
512 profiler_free (gpointer mem)
517 if (p[0]) /* free count */
519 g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already",
521 profiler_log (PROFILER_FREE,
527 #ifdef G_ENABLE_DEBUG
528 if (g_trap_free_size == p[1])
530 #endif /* G_ENABLE_DEBUG */
532 profiler_log (PROFILER_FREE,
535 memset (p + 2, 0xaa, p[1]);
537 /* for all those that miss standard_free (p); in this place, yes,
538 * we do leak all memory when profiling, and that is intentional
539 * to catch double frees. patch submissions are futile.
546 profiler_try_realloc (gpointer mem,
553 #ifdef G_ENABLE_DEBUG
554 if (g_trap_realloc_size == n_bytes)
556 #endif /* G_ENABLE_DEBUG */
558 if (mem && p[0]) /* free count */
560 g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): "
561 "memory has been freed %"G_GSIZE_FORMAT" times already",
562 p + 2, (gsize) n_bytes, p[0]);
563 profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
569 p = standard_realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes);
574 profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE);
577 profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE);
581 profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
588 profiler_realloc (gpointer mem,
591 mem = profiler_try_realloc (mem, n_bytes);
599 static GMemVTable profiler_table = {
605 profiler_try_realloc,
607 GMemVTable *glib_mem_profiler_table = &profiler_table;
609 #endif /* !G_DISABLE_CHECKS */
611 /* --- MemChunks --- */
612 #ifndef G_ALLOC_AND_FREE
613 typedef struct _GAllocator GAllocator;
614 typedef struct _GMemChunk GMemChunk;
615 #define G_ALLOC_ONLY 1
616 #define G_ALLOC_AND_FREE 2
620 guint alloc_size; /* the size of an atom */
624 g_mem_chunk_new (const gchar *name,
629 GMemChunk *mem_chunk;
630 g_return_val_if_fail (atom_size > 0, NULL);
632 mem_chunk = g_slice_new (GMemChunk);
633 mem_chunk->alloc_size = atom_size;
638 g_mem_chunk_destroy (GMemChunk *mem_chunk)
640 g_return_if_fail (mem_chunk != NULL);
642 g_slice_free (GMemChunk, mem_chunk);
646 g_mem_chunk_alloc (GMemChunk *mem_chunk)
648 g_return_val_if_fail (mem_chunk != NULL, NULL);
650 return g_slice_alloc (mem_chunk->alloc_size);
654 g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
656 g_return_val_if_fail (mem_chunk != NULL, NULL);
658 return g_slice_alloc0 (mem_chunk->alloc_size);
662 g_mem_chunk_free (GMemChunk *mem_chunk,
665 g_return_if_fail (mem_chunk != NULL);
667 g_slice_free1 (mem_chunk->alloc_size, mem);
670 void g_mem_chunk_clean (GMemChunk *mem_chunk) {}
671 void g_mem_chunk_reset (GMemChunk *mem_chunk) {}
672 void g_mem_chunk_print (GMemChunk *mem_chunk) {}
673 void g_mem_chunk_info (void) {}
674 void g_blow_chunks (void) {}
677 g_allocator_new (const gchar *name,
680 static struct _GAllocator {
686 GMemChunk *mem_chunk;
689 "GAllocator is deprecated", 1, TRUE, 0, NULL, NULL, NULL,
691 /* some (broken) GAllocator uses depend on non-NULL allocators */
692 return (void*) &dummy;
696 g_allocator_free (GAllocator *allocator)
700 #ifdef ENABLE_GC_FRIENDLY_DEFAULT
701 gboolean g_mem_gc_friendly = TRUE;
703 gboolean g_mem_gc_friendly = FALSE;
707 g_mem_init_nomessage (void)
709 #if NOT_NEEDED_FOR_NAVIT
712 const GDebugKey keys[] = {
713 { "gc-friendly", 1 },
716 if (g_mem_initialized)
718 /* don't use g_malloc/g_message here */
719 val = _g_getenv_nomalloc ("G_DEBUG", buffer);
720 flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
721 if (flags & 1) /* gc-friendly */
723 g_mem_gc_friendly = TRUE;
725 #endif /* NOT_NEEDED_FOR_NAVIT */
726 g_mem_initialized = TRUE;
730 _g_mem_thread_init_noprivate_nomessage (void)
732 /* we may only create mutexes here, locking/
733 * unlocking a mutex does not yet work.
735 g_mem_init_nomessage();
736 #ifndef G_DISABLE_CHECKS
737 gmem_profile_mutex = g_mutex_new ();
742 #include "galiasdef.c"