diff --git a/glib/gmem.c b/glib/gmem.c index dd031baf6..c76ae1774 100644 --- a/glib/gmem.c +++ b/glib/gmem.c @@ -40,9 +40,6 @@ #include "gthread.h" #include "glib_trace.h" -#define MEM_PROFILE_TABLE_SIZE 4096 - - /* notes on macros: * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and * g_mem_profile(). @@ -74,7 +71,7 @@ static GMemVTable glib_mem_vtable = { * g_slice_free(), plain malloc() with free(), and (if you're using C++) * new with delete and new[] with delete[]. Otherwise bad things can happen, * since these allocators may use different memory pools (and new/delete call - * constructors and destructors). See also g_mem_set_vtable(). + * constructors and destructors). */ /* --- functions --- */ @@ -94,7 +91,7 @@ g_malloc (gsize n_bytes) { gpointer mem; - mem = glib_mem_vtable.malloc (n_bytes); + mem = malloc (n_bytes); TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 0, 0)); if (mem) return mem; @@ -124,7 +121,7 @@ g_malloc0 (gsize n_bytes) { gpointer mem; - mem = glib_mem_vtable.calloc (1, n_bytes); + mem = calloc (1, n_bytes); TRACE (GLIB_MEM_ALLOC((void*) mem, (unsigned int) n_bytes, 1, 0)); if (mem) return mem; @@ -159,7 +156,7 @@ g_realloc (gpointer mem, if (G_LIKELY (n_bytes)) { - newmem = glib_mem_vtable.realloc (mem, n_bytes); + newmem = realloc (mem, n_bytes); TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 0)); if (newmem) return newmem; @@ -169,7 +166,7 @@ g_realloc (gpointer mem, } if (mem) - glib_mem_vtable.free (mem); + free (mem); TRACE (GLIB_MEM_REALLOC((void*) NULL, (void*)mem, 0, 0)); @@ -189,7 +186,7 @@ void g_free (gpointer mem) { if (G_LIKELY (mem)) - glib_mem_vtable.free (mem); + free (mem); TRACE(GLIB_MEM_FREE((void*) mem)); } @@ -241,7 +238,7 @@ g_try_malloc (gsize n_bytes) gpointer mem; if (G_LIKELY (n_bytes)) - mem = glib_mem_vtable.try_malloc (n_bytes); + mem = malloc (n_bytes); else mem = NULL; @@ -266,13 +263,10 @@ g_try_malloc0 (gsize n_bytes) gpointer mem; if (G_LIKELY (n_bytes)) - mem = glib_mem_vtable.try_malloc (n_bytes); + mem = calloc (1, n_bytes); else mem = NULL; - if (mem) - memset (mem, 0, n_bytes); - return mem; } @@ -296,12 +290,12 @@ g_try_realloc (gpointer mem, gpointer newmem; if (G_LIKELY (n_bytes)) - newmem = glib_mem_vtable.try_realloc (mem, n_bytes); + newmem = realloc (mem, n_bytes); else { newmem = NULL; if (mem) - glib_mem_vtable.free (mem); + free (mem); } TRACE (GLIB_MEM_REALLOC((void*) newmem, (void*)mem, (unsigned int) n_bytes, 1)); @@ -451,23 +445,6 @@ g_try_realloc_n (gpointer mem, return g_try_realloc (mem, n_blocks * n_block_bytes); } - - -static gpointer -fallback_calloc (gsize n_blocks, - gsize n_block_bytes) -{ - gsize l = n_blocks * n_block_bytes; - gpointer mem = glib_mem_vtable.malloc (l); - - if (mem) - memset (mem, 0, l); - - return mem; -} - -static gboolean vtable_set = FALSE; - /** * g_mem_is_system_malloc: * @@ -477,358 +454,53 @@ static gboolean vtable_set = FALSE; * This function is useful for avoiding an extra copy of allocated memory returned * by a non-GLib-based API. * - * A different allocator can be set using g_mem_set_vtable(). - * * Returns: if %TRUE, malloc() and g_malloc() can be mixed. + * + * Deprecated: 2.46: GLib always uses the system malloc, so this function always + * returns %TRUE. **/ gboolean g_mem_is_system_malloc (void) { - return !vtable_set; + return TRUE; } /** * g_mem_set_vtable: * @vtable: table of memory allocation routines. * - * Sets the #GMemVTable to use for memory allocation. You can use this - * to provide custom memory allocation routines. + * This function used to let you override the memory allocation function. + * However, its use was incompatible with the use of global constructors + * in GLib and GIO, because those use the GLib allocators before main is + * reached. Therefore this function is now deprecated and is just a stub. * - * The @vtable only needs to provide malloc(), realloc(), and free() - * functions; GLib can provide default implementations of the others. - * The malloc() and realloc() implementations should return %NULL on - * failure, GLib will handle error-checking for you. @vtable is copied, - * so need not persist after this function has been called. - * - * Note that this function must be called before using any other GLib - * functions. + * Deprecated: 2.46: Use other memory profiling tools instead */ void g_mem_set_vtable (GMemVTable *vtable) { - if (!vtable_set) - { - if (vtable->malloc && vtable->realloc && vtable->free) - { - glib_mem_vtable.malloc = vtable->malloc; - glib_mem_vtable.realloc = vtable->realloc; - glib_mem_vtable.free = vtable->free; - glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc; - glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc; - glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc; - vtable_set = TRUE; - } - else - g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()"); - } - else - g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup"); + g_warning (G_STRLOC ": custom memory allocation vtable not supported"); } -/* --- memory profiling and checking --- */ -#ifdef G_DISABLE_CHECKS /** * glib_mem_profiler_table: - * - * A #GMemVTable containing profiling variants of the memory - * allocation functions. Use them together with g_mem_profile() - * in order to get information about the memory allocation pattern - * of your program. + * + * Deprecated: 2.46: Use other memory profiling tools instead */ GMemVTable *glib_mem_profiler_table = &glib_mem_vtable; -void -g_mem_profile (void) -{ -} -#else /* !G_DISABLE_CHECKS */ -typedef enum { - PROFILER_FREE = 0, - PROFILER_ALLOC = 1, - PROFILER_RELOC = 2, - PROFILER_ZINIT = 4 -} ProfilerJob; -static guint *profile_data = NULL; -static gsize profile_allocs = 0; -static gsize profile_zinit = 0; -static gsize profile_frees = 0; -static GMutex gmem_profile_mutex; - -#define PROFILE_TABLE(f1,f2,f3) ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1)) - -static void -profiler_log (ProfilerJob job, - gsize n_bytes, - gboolean success) -{ - g_mutex_lock (&gmem_profile_mutex); - if (!profile_data) - { - profile_data = calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8, - sizeof (profile_data[0])); - if (!profile_data) /* memory system kiddin' me, eh? */ - { - g_mutex_unlock (&gmem_profile_mutex); - return; - } - } - - if (n_bytes < MEM_PROFILE_TABLE_SIZE) - profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, - (job & PROFILER_RELOC) != 0, - success != 0)] += 1; - else - profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, - (job & PROFILER_RELOC) != 0, - success != 0)] += 1; - if (success) - { - if (job & PROFILER_ALLOC) - { - profile_allocs += n_bytes; - if (job & PROFILER_ZINIT) - profile_zinit += n_bytes; - } - else - profile_frees += n_bytes; - } - g_mutex_unlock (&gmem_profile_mutex); -} - -static void -profile_print_locked (guint *local_data, - gboolean success) -{ - gboolean need_header = TRUE; - guint i; - - for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++) - { - glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)]; - glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)]; - glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)]; - glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)]; - - if (!t_malloc && !t_realloc && !t_free && !t_refree) - continue; - else if (need_header) - { - need_header = FALSE; - g_print (" blocks of | allocated | freed | allocated | freed | n_bytes \n"); - g_print (" n_bytes | n_times by | n_times by | n_times by | n_times by | remaining \n"); - g_print (" | malloc() | free() | realloc() | realloc() | \n"); - g_print ("===========|============|============|============|============|===========\n"); - } - if (i < MEM_PROFILE_TABLE_SIZE) - g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n", - i, t_malloc, t_free, t_realloc, t_refree, - (t_malloc - t_free + t_realloc - t_refree) * i); - else if (i >= MEM_PROFILE_TABLE_SIZE) - g_print (" >%6u | %10ld | %10ld | %10ld | %10ld | ***\n", - i, t_malloc, t_free, t_realloc, t_refree); - } - if (need_header) - g_print (" --- none ---\n"); -} /** * g_mem_profile: - * - * Outputs a summary of memory usage. - * - * It outputs the frequency of allocations of different sizes, - * the total number of bytes which have been allocated, - * the total number of bytes which have been freed, - * and the difference between the previous two values, i.e. the number of bytes - * still in use. - * - * Note that this function will not output anything unless you have - * previously installed the #glib_mem_profiler_table with g_mem_set_vtable(). + * + * GLib used to support some tools for memory profiling, but this + * no longer works. There are many other useful tools for memory + * profiling these days which can be used instead. + * + * Deprecated: 2.46: Use other memory profiling tools instead */ - void g_mem_profile (void) { - guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8]; - gsize local_allocs; - gsize local_zinit; - gsize local_frees; - - g_mutex_lock (&gmem_profile_mutex); - - local_allocs = profile_allocs; - local_zinit = profile_zinit; - local_frees = profile_frees; - - if (!profile_data) - { - g_mutex_unlock (&gmem_profile_mutex); - return; - } - - memcpy (local_data, profile_data, - (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])); - - g_mutex_unlock (&gmem_profile_mutex); - - g_print ("GLib Memory statistics (successful operations):\n"); - profile_print_locked (local_data, TRUE); - g_print ("GLib Memory statistics (failing operations):\n"); - profile_print_locked (local_data, FALSE); - g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", " - "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), " - "freed=%"G_GSIZE_FORMAT" (%.2f%%), " - "remaining=%"G_GSIZE_FORMAT"\n", - local_allocs, - local_zinit, - ((gdouble) local_zinit) / local_allocs * 100.0, - local_frees, - ((gdouble) local_frees) / local_allocs * 100.0, - local_allocs - local_frees); + g_warning (G_STRLOC ": memory profiling not supported"); } - -static gpointer -profiler_try_malloc (gsize n_bytes) -{ - gsize *p; - - p = malloc (sizeof (gsize) * 2 + n_bytes); - - if (p) - { - p[0] = 0; /* free count */ - p[1] = n_bytes; /* length */ - profiler_log (PROFILER_ALLOC, n_bytes, TRUE); - p += 2; - } - else - profiler_log (PROFILER_ALLOC, n_bytes, FALSE); - - return p; -} - -static gpointer -profiler_malloc (gsize n_bytes) -{ - gpointer mem = profiler_try_malloc (n_bytes); - - if (!mem) - g_mem_profile (); - - return mem; -} - -static gpointer -profiler_calloc (gsize n_blocks, - gsize n_block_bytes) -{ - gsize l = n_blocks * n_block_bytes; - gsize *p; - - p = calloc (1, sizeof (gsize) * 2 + l); - - if (p) - { - p[0] = 0; /* free count */ - p[1] = l; /* length */ - profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE); - p += 2; - } - else - { - profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE); - g_mem_profile (); - } - - return p; -} - -static void -profiler_free (gpointer mem) -{ - gsize *p = mem; - - p -= 2; - if (p[0]) /* free count */ - { - g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already", - p + 2, p[0]); - profiler_log (PROFILER_FREE, - p[1], /* length */ - FALSE); - } - else - { - profiler_log (PROFILER_FREE, - p[1], /* length */ - TRUE); - memset (p + 2, 0xaa, p[1]); - - /* for all those that miss free (p); in this place, yes, - * we do leak all memory when profiling, and that is intentional - * to catch double frees. patch submissions are futile. - */ - } - p[0] += 1; -} - -static gpointer -profiler_try_realloc (gpointer mem, - gsize n_bytes) -{ - gsize *p = mem; - - p -= 2; - - if (mem && p[0]) /* free count */ - { - g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): " - "memory has been freed %"G_GSIZE_FORMAT" times already", - p + 2, (gsize) n_bytes, p[0]); - profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); - - return NULL; - } - else - { - p = realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes); - - if (p) - { - if (mem) - profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE); - p[0] = 0; - p[1] = n_bytes; - profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE); - p += 2; - } - else - profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); - - return p; - } -} - -static gpointer -profiler_realloc (gpointer mem, - gsize n_bytes) -{ - mem = profiler_try_realloc (mem, n_bytes); - - if (!mem) - g_mem_profile (); - - return mem; -} - -static GMemVTable profiler_table = { - profiler_malloc, - profiler_realloc, - profiler_free, - profiler_calloc, - profiler_try_malloc, - profiler_try_realloc, -}; -GMemVTable *glib_mem_profiler_table = &profiler_table; - -#endif /* !G_DISABLE_CHECKS */ diff --git a/glib/gmem.h b/glib/gmem.h index 10fee07c7..031271da2 100644 --- a/glib/gmem.h +++ b/glib/gmem.h @@ -45,6 +45,8 @@ G_BEGIN_DECLS * A set of functions used to perform memory allocation. The same #GMemVTable must * be used for all allocations in the same program; a call to g_mem_set_vtable(), * if it exists, should be prior to any use of GLib. + * + * This functions related to this has been deprecated in 2.46, and no longer work. */ typedef struct _GMemVTable GMemVTable; @@ -351,9 +353,9 @@ struct _GMemVTable { gpointer (*try_realloc) (gpointer mem, gsize n_bytes); }; -GLIB_AVAILABLE_IN_ALL +GLIB_DEPRECATED_IN_2_46 void g_mem_set_vtable (GMemVTable *vtable); -GLIB_AVAILABLE_IN_ALL +GLIB_DEPRECATED_IN_2_46 gboolean g_mem_is_system_malloc (void); GLIB_VAR gboolean g_mem_gc_friendly; @@ -361,7 +363,7 @@ GLIB_VAR gboolean g_mem_gc_friendly; /* Memory profiler and checker, has to be enabled via g_mem_set_vtable() */ GLIB_VAR GMemVTable *glib_mem_profiler_table; -GLIB_AVAILABLE_IN_ALL +GLIB_DEPRECATED_IN_2_46 void g_mem_profile (void); G_END_DECLS