/* GLIB sliced memory - fast concurrent memory chunk allocator * Copyright (C) 2005 Tim Janik * * SPDX-License-Identifier: LGPL-2.1-or-later * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ /* MT safe */ #include "config.h" #include "glibconfig.h" #include #include #include "gslice.h" #include "gmem.h" /* gslice.h */ #include "glib_trace.h" #include "gprintf.h" /** * SECTION:memory_slices * @title: Memory Slices * @short_description: efficient way to allocate groups of equal-sized * chunks of memory * * GSlice was a space-efficient and multi-processing scalable way to allocate * equal sized pieces of memory. Since GLib 2.76, its implementation has been * removed and it calls g_malloc() and g_free_sized(), because the performance * of the system-default allocators has improved on all platforms since GSlice * was written. * * The GSlice APIs have not been deprecated, as they are widely in use and doing * so would be very disruptive for little benefit. * * New code should be written using g_new()/g_malloc() and g_free_sized() or * g_free(). There is no particular benefit in porting existing code away from * g_slice_new()/g_slice_free() unless it’s being rewritten anyway. * * Here is an example for using the slice allocator: * |[ * gchar *mem[10000]; * gint i; * * // Allocate 10000 blocks. * for (i = 0; i < 10000; i++) * { * mem[i] = g_slice_alloc (50); * * // Fill in the memory with some junk. * for (j = 0; j < 50; j++) * mem[i][j] = i * j; * } * * // Now free all of the blocks. * for (i = 0; i < 10000; i++) * g_slice_free1 (50, mem[i]); * ]| * * And here is an example for using the using the slice allocator * with data structures: * |[ * GRealArray *array; * * // Allocate one block, using the g_slice_new() macro. * array = g_slice_new (GRealArray); * * // We can now use array just like a normal pointer to a structure. * array->data = NULL; * array->len = 0; * array->alloc = 0; * array->zero_terminated = (zero_terminated ? 1 : 0); * array->clear = (clear ? 1 : 0); * array->elt_size = elt_size; * * // We can free the block, so it can be reused. * g_slice_free (GRealArray, array); * ]| */ /* --- auxiliary functions --- */ void g_slice_set_config (GSliceConfig ckey, gint64 value) { /* deprecated, no implementation */ } gint64 g_slice_get_config (GSliceConfig ckey) { /* deprecated, no implementation */ return 0; } gint64* g_slice_get_config_state (GSliceConfig ckey, gint64 address, guint *n_values) { /* deprecated, no implementation */ return NULL; } /* --- API functions --- */ /** * g_slice_new: * @type: the type to allocate, typically a structure name * * A convenience macro to allocate a block of memory from the * slice allocator. * * It calls g_slice_alloc() with `sizeof (@type)` and casts the * returned pointer to a pointer of the given type, avoiding a type * cast in the source code. * * This can never return %NULL as the minimum allocation size from * `sizeof (@type)` is 1 byte. * * Since GLib 2.76 this always uses the system malloc() implementation * internally. * * Returns: (not nullable): a pointer to the allocated block, cast to a pointer * to @type * * Since: 2.10 */ /** * g_slice_new0: * @type: the type to allocate, typically a structure name * * A convenience macro to allocate a block of memory from the * slice allocator and set the memory to 0. * * It calls g_slice_alloc0() with `sizeof (@type)` * and casts the returned pointer to a pointer of the given type, * avoiding a type cast in the source code. * * This can never return %NULL as the minimum allocation size from * `sizeof (@type)` is 1 byte. * * Since GLib 2.76 this always uses the system malloc() implementation * internally. * * Returns: (not nullable): a pointer to the allocated block, cast to a pointer * to @type * * Since: 2.10 */ /** * g_slice_dup: * @type: the type to duplicate, typically a structure name * @mem: (not nullable): the memory to copy into the allocated block * * A convenience macro to duplicate a block of memory using * the slice allocator. * * It calls g_slice_copy() with `sizeof (@type)` * and casts the returned pointer to a pointer of the given type, * avoiding a type cast in the source code. * * This can never return %NULL. * * Since GLib 2.76 this always uses the system malloc() implementation * internally. * * Returns: (not nullable): a pointer to the allocated block, cast to a pointer * to @type * * Since: 2.14 */ /** * g_slice_free: * @type: the type of the block to free, typically a structure name * @mem: (nullable): a pointer to the block to free * * A convenience macro to free a block of memory that has * been allocated from the slice allocator. * * It calls g_slice_free1() using `sizeof (type)` * as the block size. * Note that the exact release behaviour can be changed with the * [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable. * * If @mem is %NULL, this macro does nothing. * * Since GLib 2.76 this always uses the system free() implementation internally. * * Since: 2.10 */ /** * g_slice_free_chain: * @type: the type of the @mem_chain blocks * @mem_chain: (nullable): a pointer to the first block of the chain * @next: the field name of the next pointer in @type * * Frees a linked list of memory blocks of structure type @type. * * The memory blocks must be equal-sized, allocated via * g_slice_alloc() or g_slice_alloc0() and linked together by * a @next pointer (similar to #GSList). The name of the * @next field in @type is passed as third argument. * Note that the exact release behaviour can be changed with the * [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable. * * If @mem_chain is %NULL, this function does nothing. * * Since GLib 2.76 this always uses the system free() implementation internally. * * Since: 2.10 */ /** * g_slice_alloc: * @block_size: the number of bytes to allocate * * Allocates a block of memory from the libc allocator. * * The block address handed out can be expected to be aligned * to at least `1 * sizeof (void*)`. * * Since GLib 2.76 this always uses the system malloc() implementation * internally. * * Returns: (nullable): a pointer to the allocated memory block, which will * be %NULL if and only if @mem_size is 0 * * Since: 2.10 */ gpointer g_slice_alloc (gsize mem_size) { gpointer mem; mem = g_malloc (mem_size); TRACE (GLIB_SLICE_ALLOC((void*)mem, mem_size)); return mem; } /** * g_slice_alloc0: * @block_size: the number of bytes to allocate * * Allocates a block of memory via g_slice_alloc() and initializes * the returned memory to 0. * * Since GLib 2.76 this always uses the system malloc() implementation * internally. * * Returns: (nullable): a pointer to the allocated block, which will be %NULL * if and only if @mem_size is 0 * * Since: 2.10 */ gpointer g_slice_alloc0 (gsize mem_size) { gpointer mem = g_slice_alloc (mem_size); if (mem) memset (mem, 0, mem_size); return mem; } /** * g_slice_copy: * @block_size: the number of bytes to allocate * @mem_block: the memory to copy * * Allocates a block of memory from the slice allocator * and copies @block_size bytes into it from @mem_block. * * @mem_block must be non-%NULL if @block_size is non-zero. * * Since GLib 2.76 this always uses the system malloc() implementation * internally. * * Returns: (nullable): a pointer to the allocated memory block, * which will be %NULL if and only if @mem_size is 0 * * Since: 2.14 */ gpointer g_slice_copy (gsize mem_size, gconstpointer mem_block) { gpointer mem = g_slice_alloc (mem_size); if (mem) memcpy (mem, mem_block, mem_size); return mem; } /** * g_slice_free1: * @block_size: the size of the block * @mem_block: (nullable): a pointer to the block to free * * Frees a block of memory. * * The memory must have been allocated via g_slice_alloc() or * g_slice_alloc0() and the @block_size has to match the size * specified upon allocation. Note that the exact release behaviour * can be changed with the [`G_DEBUG=gc-friendly`][G_DEBUG] environment * variable. * * If @mem_block is %NULL, this function does nothing. * * Since GLib 2.76 this always uses the system free_sized() implementation * internally. * * Since: 2.10 */ void g_slice_free1 (gsize mem_size, gpointer mem_block) { if (G_UNLIKELY (g_mem_gc_friendly && mem_block)) memset (mem_block, 0, mem_size); g_free_sized (mem_block, mem_size); TRACE (GLIB_SLICE_FREE((void*)mem_block, mem_size)); } /** * g_slice_free_chain_with_offset: * @block_size: the size of the blocks * @mem_chain: (nullable): a pointer to the first block of the chain * @next_offset: the offset of the @next field in the blocks * * Frees a linked list of memory blocks of structure type @type. * * The memory blocks must be equal-sized, allocated via * g_slice_alloc() or g_slice_alloc0() and linked together by a * @next pointer (similar to #GSList). The offset of the @next * field in each block is passed as third argument. * Note that the exact release behaviour can be changed with the * [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable. * * If @mem_chain is %NULL, this function does nothing. * * Since GLib 2.76 this always uses the system free_sized() implementation * internally. * * Since: 2.10 */ void g_slice_free_chain_with_offset (gsize mem_size, gpointer mem_chain, gsize next_offset) { gpointer slice = mem_chain; while (slice) { guint8 *current = slice; slice = *(gpointer *) (current + next_offset); if (G_UNLIKELY (g_mem_gc_friendly)) memset (current, 0, mem_size); g_free_sized (current, mem_size); } } #ifdef G_ENABLE_DEBUG void g_slice_debug_tree_statistics (void) { g_fprintf (stderr, "GSlice: Implementation dropped in GLib 2.76\n"); } #endif /* G_ENABLE_DEBUG */