From 3f9d65375e46a49e3be7bf1ca7533b3a9ac310b4 Mon Sep 17 00:00:00 2001 From: Tim Janik Date: Tue, 20 Dec 2005 17:35:02 +0000 Subject: [PATCH] added mem_error() and mem_assert() to test and handle errors without Tue Dec 20 18:14:14 2005 Tim Janik * glib/gslice.[hc]: added mem_error() and mem_assert() to test and handle errors without depending on gmessage.c which might not be setup when the error occours. removed G_SLICE_CONFIG_ALWAYS_FREE config option, fixed the code so always freeing can be achieved by adjusting the working set time to 0 with G_SLICE_CONFIG_WORKING_SET_MSECS. added G_SLICE_CONFIG_COLOR_INCREMENT to test different color increments (mainly 0 and 1). reduced the minimum block size to 128 bytes, to minimize wastage if small amounts of differently sized structrues are allocated, this does come at a performance cost of roughly 5% though. fixed up block alignment calculation, so it works for varying block sizes. only use strerror() not g_strerror() since the latter depends on working GQuark and GSlice. mem_error(): implemented in terms of fprintf and vfprintf. * tests/slice-color.c: new program to test cache colorization effects. * tests/slice-test.c: trade G_SLICE_CONFIG_ALWAYS_FREE for 0 duration G_SLICE_CONFIG_WORKING_SET_MSECS. --- ChangeLog | 22 ++++++ ChangeLog.pre-2-10 | 22 ++++++ ChangeLog.pre-2-12 | 22 ++++++ glib/gslice.c | 103 ++++++++++++++++++-------- glib/gslice.h | 2 +- tests/Makefile.am | 3 + tests/slice-color.c | 173 ++++++++++++++++++++++++++++++++++++++++++++ tests/slice-test.c | 2 +- 8 files changed, 317 insertions(+), 32 deletions(-) create mode 100644 tests/slice-color.c diff --git a/ChangeLog b/ChangeLog index 0805b476b..a17931884 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +Tue Dec 20 18:14:14 2005 Tim Janik + + * glib/gslice.[hc]: added mem_error() and mem_assert() to test and + handle errors without depending on gmessage.c which might not be + setup when the error occours. + removed G_SLICE_CONFIG_ALWAYS_FREE config option, fixed the code so + always freeing can be achieved by adjusting the working set time to + 0 with G_SLICE_CONFIG_WORKING_SET_MSECS. + added G_SLICE_CONFIG_COLOR_INCREMENT to test different color increments + (mainly 0 and 1). reduced the minimum block size to 128 bytes, to + minimize wastage if small amounts of differently sized structrues are + allocated, this does come at a performance cost of roughly 5% though. + fixed up block alignment calculation, so it works for varying + block sizes. only use strerror() not g_strerror() since the latter + depends on working GQuark and GSlice. + mem_error(): implemented in terms of fprintf and vfprintf. + + * tests/slice-color.c: new program to test cache colorization effects. + + * tests/slice-test.c: trade G_SLICE_CONFIG_ALWAYS_FREE for 0 duration + G_SLICE_CONFIG_WORKING_SET_MSECS. + 2005-12-17 Matthias Clasen * glib/goption.c (parse_short_option): Set an error in all diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 0805b476b..a17931884 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,25 @@ +Tue Dec 20 18:14:14 2005 Tim Janik + + * glib/gslice.[hc]: added mem_error() and mem_assert() to test and + handle errors without depending on gmessage.c which might not be + setup when the error occours. + removed G_SLICE_CONFIG_ALWAYS_FREE config option, fixed the code so + always freeing can be achieved by adjusting the working set time to + 0 with G_SLICE_CONFIG_WORKING_SET_MSECS. + added G_SLICE_CONFIG_COLOR_INCREMENT to test different color increments + (mainly 0 and 1). reduced the minimum block size to 128 bytes, to + minimize wastage if small amounts of differently sized structrues are + allocated, this does come at a performance cost of roughly 5% though. + fixed up block alignment calculation, so it works for varying + block sizes. only use strerror() not g_strerror() since the latter + depends on working GQuark and GSlice. + mem_error(): implemented in terms of fprintf and vfprintf. + + * tests/slice-color.c: new program to test cache colorization effects. + + * tests/slice-test.c: trade G_SLICE_CONFIG_ALWAYS_FREE for 0 duration + G_SLICE_CONFIG_WORKING_SET_MSECS. + 2005-12-17 Matthias Clasen * glib/goption.c (parse_short_option): Set an error in all diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 0805b476b..a17931884 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,25 @@ +Tue Dec 20 18:14:14 2005 Tim Janik + + * glib/gslice.[hc]: added mem_error() and mem_assert() to test and + handle errors without depending on gmessage.c which might not be + setup when the error occours. + removed G_SLICE_CONFIG_ALWAYS_FREE config option, fixed the code so + always freeing can be achieved by adjusting the working set time to + 0 with G_SLICE_CONFIG_WORKING_SET_MSECS. + added G_SLICE_CONFIG_COLOR_INCREMENT to test different color increments + (mainly 0 and 1). reduced the minimum block size to 128 bytes, to + minimize wastage if small amounts of differently sized structrues are + allocated, this does come at a performance cost of roughly 5% though. + fixed up block alignment calculation, so it works for varying + block sizes. only use strerror() not g_strerror() since the latter + depends on working GQuark and GSlice. + mem_error(): implemented in terms of fprintf and vfprintf. + + * tests/slice-color.c: new program to test cache colorization effects. + + * tests/slice-test.c: trade G_SLICE_CONFIG_ALWAYS_FREE for 0 duration + G_SLICE_CONFIG_WORKING_SET_MSECS. + 2005-12-17 Matthias Clasen * glib/goption.c (parse_short_option): Set an error in all diff --git a/glib/gslice.c b/glib/gslice.c index 5e635e33a..c9979d3ca 100644 --- a/glib/gslice.c +++ b/glib/gslice.c @@ -19,7 +19,6 @@ /* MT safe */ #define _XOPEN_SOURCE 600 /* posix_memalign() */ #include /* posix_memalign() */ -#include /* assert() for nomessage phase */ #include #include #include "config.h" @@ -86,7 +85,7 @@ * a chunk size specific maximum to limit magazine storage sizes to roughly * 16KB. * [4] allocating ca. 8 chunks per block/page keeps a good balance between - * external and internal fragmentation (<= 12.5%) [Bonwick94] + * external and internal fragmentation (<= 12.5%). [Bonwick94] */ /* --- macros and constants --- */ @@ -102,7 +101,7 @@ #define MAX_SLAB_INDEX(al) (SLAB_INDEX (al, MAX_SLAB_CHUNK_SIZE (al)) + 1) #define SLAB_INDEX(al, asize) ((asize) / P2ALIGNMENT - 1) /* asize must be P2ALIGNMENT aligned */ #define SLAB_CHUNK_SIZE(al, ix) (((ix) + 1) * P2ALIGNMENT) -#define SLAB_PAGE_SIZE(al,csz) (ALIGN (8 * (csz) + SLAB_INFO_SIZE, (al)->min_page_size)) +#define SLAB_BPAGE_SIZE(al,csz) (8 * (csz) + SLAB_INFO_SIZE) /* optimized version of ALIGN (size, P2ALIGNMENT) */ #if GLIB_SIZEOF_SIZE_T * 2 == 8 /* P2ALIGNMENT */ @@ -113,6 +112,10 @@ #define P2ALIGN(size) ALIGN (size, P2ALIGNMENT) #endif +/* special helpers to avoid gmessage.c dependency */ +static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2); +#define mem_assert(cond) do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0) + /* --- structures --- */ typedef struct _ChunkLink ChunkLink; typedef struct _SlabInfo SlabInfo; @@ -137,8 +140,8 @@ typedef struct { typedef struct { gboolean always_malloc; gboolean bypass_magazines; - gboolean always_free; gsize working_set_msecs; + guint color_increment; } SliceConfig; typedef struct { /* const after initialization */ @@ -178,8 +181,8 @@ static Allocator allocator[1] = { { 0, }, }; static SliceConfig slice_config = { FALSE, /* always_malloc */ FALSE, /* bypass_magazines */ - FALSE, /* always_free */ 15 * 1000, /* working_set_msecs */ + 1, /* color increment, alt: 0x7fffffff */ }; /* --- auxillary funcitons --- */ @@ -196,12 +199,11 @@ g_slice_set_config (GSliceConfig ckey, case G_SLICE_CONFIG_BYPASS_MAGAZINES: slice_config.bypass_magazines = value != 0; break; - case G_SLICE_CONFIG_ALWAYS_FREE: - slice_config.always_free = value != 0; - break; case G_SLICE_CONFIG_WORKING_SET_MSECS: slice_config.working_set_msecs = value; break; + case G_SLICE_CONFIG_COLOR_INCREMENT: + slice_config.color_increment = value; default: ; } } @@ -215,12 +217,12 @@ g_slice_get_config (GSliceConfig ckey) return slice_config.always_malloc; case G_SLICE_CONFIG_BYPASS_MAGAZINES: return slice_config.bypass_magazines; - case G_SLICE_CONFIG_ALWAYS_FREE: - return slice_config.always_free; case G_SLICE_CONFIG_WORKING_SET_MSECS: return slice_config.working_set_msecs; case G_SLICE_CONFIG_CHUNK_SIZES: return MAX_SLAB_INDEX (allocator); + case G_SLICE_CONFIG_COLOR_INCREMENT: + return slice_config.color_increment; default: return 0; } @@ -251,28 +253,35 @@ g_slice_get_config_state (GSliceConfig ckey, static void g_slice_init_nomessage (void) { -#ifdef G_OS_WIN32 - SYSTEM_INFO system_info; -#endif /* we may not use g_error() or friends here */ - assert (sys_page_size == 0); + mem_assert (sys_page_size == 0); + mem_assert (MIN_MAGAZINE_SIZE >= 4); #ifdef G_OS_WIN32 - GetSystemInfo (&system_info); - sys_page_size = system_info.dwPageSize; + { + SYSTEM_INFO system_info; + GetSystemInfo (&system_info); + sys_page_size = system_info.dwPageSize; + } #else sys_page_size = sysconf (_SC_PAGESIZE); /* = sysconf (_SC_PAGE_SIZE); = getpagesize(); */ #endif - assert (sys_page_size >= 2 * LARGEALIGNMENT); + mem_assert (sys_page_size >= 2 * LARGEALIGNMENT); + mem_assert ((sys_page_size & (sys_page_size - 1)) == 0); allocator->config = slice_config; allocator->min_page_size = sys_page_size; #if HAVE_POSIX_MEMALIGN || HAVE_MEMALIGN /* allow allocation of pages up to 8KB (with 8KB alignment). * this is useful because many medium to large sized structures * fit less than 8 times (see [4]) into 4KB pages. + * we allow very small page sizes here, to reduce wastage in + * threads if only small allocations are required (this does + * bear the risk of incresing allocation times and fragmentation + * though). */ allocator->min_page_size = MAX (allocator->min_page_size, 4096); allocator->max_page_size = MAX (allocator->min_page_size, 8192); + allocator->min_page_size = MIN (allocator->min_page_size, 128); #else /* we can only align to system page size */ allocator->max_page_size = sys_page_size; @@ -461,7 +470,7 @@ magazine_chain_prepare_fields (ChunkLink *magazine_chunks) ChunkLink *chunk2; ChunkLink *chunk3; ChunkLink *chunk4; - g_assert (MIN_MAGAZINE_SIZE >= 4); + /* checked upon initialization: mem_assert (MIN_MAGAZINE_SIZE >= 4); */ /* ensure a magazine with at least 4 unused data pointers */ chunk1 = magazine_chain_pop_head (&magazine_chunks); chunk2 = magazine_chain_pop_head (&magazine_chunks); @@ -490,8 +499,7 @@ magazine_cache_trim (Allocator *allocator, /* trim magazine cache from tail */ ChunkLink *current = magazine_chain_prev (allocator->magazines[ix]); ChunkLink *trash = NULL; - while (allocator->config.always_free || - ABS (stamp - magazine_chain_uint_stamp (current)) > allocator->config.working_set_msecs) + while (ABS (stamp - magazine_chain_uint_stamp (current)) >= allocator->config.working_set_msecs) { /* unlink */ ChunkLink *prev = magazine_chain_prev (current); @@ -643,7 +651,7 @@ thread_memory_magazine1_reload (ThreadMemory *tmem, guint ix) { Magazine *mag = &tmem->magazine1[ix]; - g_assert (mag->chunks == NULL); /* ensure that we may reset mag->count */ + mem_assert (mag->chunks == NULL); /* ensure that we may reset mag->count */ mag->count = 0; mag->chunks = magazine_cache_pop_magazine (ix, &mag->count); } @@ -859,6 +867,15 @@ allocator_slab_stack_push (Allocator *allocator, allocator->slab_stack[ix] = sinfo; } +static gsize +allocator_aligned_page_size (Allocator *allocator, + gsize n_bytes) +{ + gsize val = 1 << g_bit_storage (n_bytes - 1); + val = MAX (val, allocator->min_page_size); + return val; +} + static void allocator_add_slab (Allocator *allocator, guint ix, @@ -867,17 +884,24 @@ allocator_add_slab (Allocator *allocator, ChunkLink *chunk; SlabInfo *sinfo; gsize addr, padding, n_chunks, color = 0; - gsize page_size = SLAB_PAGE_SIZE (allocator, chunk_size); + gsize page_size = allocator_aligned_page_size (allocator, SLAB_BPAGE_SIZE (allocator, chunk_size)); /* allocate 1 page for the chunks and the slab */ gpointer aligned_memory = allocator_memalign (page_size, page_size - NATIVE_MALLOC_PADDING); guint8 *mem = aligned_memory; guint i; if (!mem) - g_error ("%s: failed to allocate %lu bytes: %s", "GSlicedMemory", (gulong) (page_size - NATIVE_MALLOC_PADDING), g_strerror (errno)); + { + const gchar *syserr = "unknown error"; +#if HAVE_STRERROR + syserr = strerror (errno); +#endif + mem_error ("failed to allocate %u bytes (alignment: %u): %s\n", + (guint) (page_size - NATIVE_MALLOC_PADDING), (guint) page_size, syserr); + } /* mask page adress */ addr = ((gsize) mem / page_size) * page_size; /* assert alignment */ - g_assert (aligned_memory == (gpointer) addr); + mem_assert (aligned_memory == (gpointer) addr); /* basic slab info setup */ sinfo = (SlabInfo*) (mem + page_size - SLAB_INFO_SIZE); sinfo->n_allocated = 0; @@ -888,7 +912,7 @@ allocator_add_slab (Allocator *allocator, if (padding) { color = (allocator->color_accu * P2ALIGNMENT) % padding; - allocator->color_accu += 1; /* alternatively: + 0x7fffffff */ + allocator->color_accu += allocator->config.color_increment; } /* add chunks to free list */ chunk = (ChunkLink*) (mem + color); @@ -928,13 +952,13 @@ slab_allocator_free_chunk (gsize chunk_size, ChunkLink *chunk; gboolean was_empty; guint ix = SLAB_INDEX (allocator, chunk_size); - gsize page_size = SLAB_PAGE_SIZE (allocator, chunk_size); + gsize page_size = allocator_aligned_page_size (allocator, SLAB_BPAGE_SIZE (allocator, chunk_size)); gsize addr = ((gsize) mem / page_size) * page_size; /* mask page adress */ guint8 *page = (guint8*) addr; SlabInfo *sinfo = (SlabInfo*) (page + page_size - SLAB_INFO_SIZE); /* assert valid chunk count */ - g_assert (sinfo->n_allocated > 0); + mem_assert (sinfo->n_allocated > 0); /* add chunk to free list */ was_empty = sinfo->chunks == NULL; chunk = (ChunkLink*) mem; @@ -999,8 +1023,8 @@ allocator_memalign (gsize alignment, err = errno; #else /* simplistic non-freeing page allocator */ - g_assert (alignment == sys_page_size); - g_assert (memsize <= sys_page_size); + mem_assert (alignment == sys_page_size); + mem_assert (memsize <= sys_page_size); if (!compat_valloc_trash) { const guint n_pages = 16; @@ -1030,10 +1054,29 @@ allocator_memfree (gsize memsize, #if HAVE_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_VALLOC free (mem); #else - g_assert (memsize <= sys_page_size); + mem_assert (memsize <= sys_page_size); g_trash_stack_push (&compat_valloc_trash, mem); #endif } +#include + +static void +mem_error (const char *format, + ...) +{ + const char *pname; + va_list args; + /* at least, put out "MEMORY-ERROR", in case we segfault during the rest of the function */ + fputs ("\n***MEMORY-ERROR***: ", stderr); + pname = g_get_prgname(); + fprintf (stderr, "%s[%u]: GSlice: ", pname ? pname : "", getpid()); + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + fputs ("\n", stderr); + _exit (1); +} + #define __G_SLICE_C__ #include "galiasdef.c" diff --git a/glib/gslice.h b/glib/gslice.h index a3201481e..93b545a7c 100644 --- a/glib/gslice.h +++ b/glib/gslice.h @@ -63,8 +63,8 @@ void g_slice_free_chain_with_offset (gsize block_size, typedef enum { G_SLICE_CONFIG_ALWAYS_MALLOC = 1, G_SLICE_CONFIG_BYPASS_MAGAZINES, - G_SLICE_CONFIG_ALWAYS_FREE, G_SLICE_CONFIG_WORKING_SET_MSECS, + G_SLICE_CONFIG_COLOR_INCREMENT, G_SLICE_CONFIG_CHUNK_SIZES, G_SLICE_CONFIG_CONTENTION_COUNTER } GSliceConfig; diff --git a/tests/Makefile.am b/tests/Makefile.am index 763a61aef..9347751a3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -92,6 +92,7 @@ test_programs = \ shell-test \ slist-test \ slice-test \ + slice-color \ spawn-test \ $(spawn_test_win32_gui) \ strfunc-test \ @@ -155,6 +156,8 @@ shell_test_LDADD = $(progs_ldadd) slist_test_LDADD = $(progs_ldadd) slice_test_SOURCES = slice-test.c memchunks.c slice_test_LDADD = $(thread_ldadd) +slice_color_SOURCES = slice-color.c memchunks.c +slice_color_LDADD = $(thread_ldadd) spawn_test_LDADD = $(progs_ldadd) strfunc_test_LDADD = $(progs_ldadd) string_test_LDADD = $(progs_ldadd) diff --git a/tests/slice-color.c b/tests/slice-color.c new file mode 100644 index 000000000..85ad62afe --- /dev/null +++ b/tests/slice-color.c @@ -0,0 +1,173 @@ +/* GLIB sliced memory - fast threaded memory chunk allocator + * Copyright (C) 2005 Tim Janik + * + * 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include +#include + +#define ALIGN(size, base) ((base) * (gsize) (((size) + (base) - 1) / (base))) + +static gdouble parse_memsize (const gchar *cstring); +static void usage (void); + +static void +fill_memory (guint **mem, + guint n, + guint val) +{ + guint j, o = 0; + for (j = 0; j < n; j++) + mem[j][o] = val; +} + +static guint64 +access_memory3 (guint **mema, + guint **memb, + guint **memd, + guint n, + guint64 repeats) +{ + guint64 accu = 0, i, j; + const guint o = 0; + for (i = 0; i < repeats; i++) + { + for (j = 1; j < n; j += 2) + memd[j][o] = mema[j][o] + memb[j][o]; + } + for (i = 0; i < repeats; i++) + for (j = 0; j < n; j++) + accu += memd[j][o]; + return accu; +} + +static void +touch_mem (guint64 block_size, + guint64 n_blocks, + guint64 repeats) +{ + guint64 j, accu, n = n_blocks; + guint **mema = g_new (guint*, n); + for (j = 0; j < n; j++) + mema[j] = g_slice_alloc (block_size); + guint **memb = g_new (guint*, n); + for (j = 0; j < n; j++) + memb[j] = g_slice_alloc (block_size); + guint **memc = g_new (guint*, n); + for (j = 0; j < n; j++) + memc[j] = g_slice_alloc (block_size); + + GTimer *timer = g_timer_new(); + fill_memory (mema, n, 2); + fill_memory (memb, n, 3); + fill_memory (memc, n, 4); + access_memory3 (mema, memb, memc, n, 3); + g_timer_start (timer); + accu = access_memory3 (mema, memb, memc, n, repeats); + g_timer_stop (timer); + + g_print ("Access-time = %fs\n", g_timer_elapsed (timer, NULL)); + g_assert (accu / repeats == (2 + 3) * n / 2 + 4 * n / 2); + + for (j = 0; j < n; j++) + { + g_slice_free1 (block_size, mema[j]); + g_slice_free1 (block_size, memb[j]); + g_slice_free1 (block_size, memc[j]); + } + g_timer_destroy (timer); + g_free (mema); + g_free (memb); + g_free (memc); +} + +static void +usage (void) +{ + g_print ("Usage: slice-color [memory-size] [repeats] [colorization]\n"); +} + +int +main (int argc, + char *argv[]) +{ + guint64 block_size = 512, area_size = 1024 * 1024, n_blocks, repeats = 1000000; + + if (argc > 1) + block_size = parse_memsize (argv[1]); + else + { + usage(); + block_size = 512; + } + if (argc > 2) + area_size = parse_memsize (argv[2]); + if (argc > 3) + repeats = parse_memsize (argv[3]); + if (argc > 4) + g_slice_set_config (G_SLICE_CONFIG_COLOR_INCREMENT, parse_memsize (argv[4])); + + /* figure number of blocks from block and area size. + * divide area by 3 because touch_mem() allocates 3 areas + */ + n_blocks = area_size / 3 / ALIGN (block_size, sizeof (gsize) * 2); + + /* basic sanity checks */ + if (!block_size || !n_blocks || block_size >= area_size) + { + g_printerr ("Invalid arguments: block-size=%llu memory-size=%llu\n", block_size, area_size); + usage(); + return 1; + } + + g_printerr ("Will allocate and touch %llu blocks of %llu bytes (= %llu bytes) %llu times with color increment: 0x%08llx\n", + n_blocks, block_size, n_blocks * block_size, repeats, g_slice_get_config (G_SLICE_CONFIG_COLOR_INCREMENT)); + + touch_mem (block_size, n_blocks, repeats); + + return 0; +} + +static gdouble +parse_memsize (const gchar *cstring) +{ + gchar *mem = g_strdup (cstring); + gchar *string = g_strstrip (mem); + guint l = strlen (string); + gdouble f = 0; + switch (l ? string[l - 1] : 0) + { + case 'k': f = 1000; break; + case 'K': f = 1024; break; + case 'm': f = 1000000; break; + case 'M': f = 1024 * 1024; break; + case 'g': f = 1000000000; break; + case 'G': f = 1024 * 1024 * 1024; break; + } + if (f) + string[l - 1] = 0; + gchar *derr = NULL; + gdouble msize = g_ascii_strtod (string, &derr); + g_free (mem); + if (derr && *derr) + { + g_printerr ("failed to parse number at: %s\n", derr); + msize = 0; + } + if (f) + msize *= f; + return msize; +} diff --git a/tests/slice-test.c b/tests/slice-test.c index fbbd081bd..f0b5b20af 100644 --- a/tests/slice-test.c +++ b/tests/slice-test.c @@ -220,7 +220,7 @@ main (int argc, mode = "old memchunks"; break; case 'f': /* eager freeing */ - g_slice_set_config (G_SLICE_CONFIG_ALWAYS_FREE, TRUE); + g_slice_set_config (G_SLICE_CONFIG_WORKING_SET_MSECS, 0); clean_memchunks = TRUE; emode = " with eager freeing"; break;