Hi there,

After experiencing MAX_OBJECTS-related excessive swapping on Invidious
that allowed Saromok's souped-up goblins to poison and kill my
character, I've decided to take another look at memory management.

I may be missing some historical context for why things are the way they
currently are in Crossfire, so I welcome feedback on what these proposed
changes might do or not do.

The rationale for each change is included in each patch, but reproduced
here for convenience:


Subject: [PATCH 1/2] Retire MAX_OBJECTS

MAX_OBJECTS has probably outlived its usefulness. It was previously "no
hard limit," only serving to trigger map swapping immediately after
loading a map, if the number of used objects exceeded MAX_OBJECTS.

At worse case, MAX_OBJECTS causes an O(n^2) search and O(n) swaps, where
n is the number of maps in memory. This happens immediately after
loading a very large map. The server takes O(n) to search for the map
with the smallest remaining timeout and swaps it, and does this n times
or until enough memory is freed. If the other maps are small, this does
not free much memory and causes the "performance hit" mentioned in the
comments. This was observed on Invidious, where the server experienced
delays of up to 700 ms immediately after loading a large map due to
excessive swapping.

Removing MAX_OBJECTS does not significantly change the server's
allocation pattern because the server never frees memory (it maintains
an internal free list) and because maps are swapped out based on timeout
at the end of each tick anyway.


Subject: [PATCH 2/2] Retire object allocator

The object allocator allocates OBJ_EXPAND objects at a time and manages
its own free list. It is faster at allocating many objects at once, but
defeats memory debuggers and mitigation techniques. It also does not
return unused memory to the operating system.

Rewrite object_new() to always allocate memory using calloc(). This will
incur some memory overhead since an object struct does not fit perfectly
into a nice allocator slab size.

object_free2() adds freed objects to a free list that is reclaimed at
the end of each server tick. It cannot immediately free object memory,
because some callers expect to be able to query it for FLAG_FREED to
detect object removal.


These changes were tested locally (mostly by running a character around)
with 1) clang -fsanitize=address, which did not report any errors, and
2) with Jemalloc statistics enabled (see attached, jemalloc.out).

As expected, after the change, the allocator bin seeing the most
activity was 768 bytes (struct object is 656 bytes on x86-64).

-- 
Kevin Zheng
kevinz5...@gmail.com | kev...@berkeley.edu
XMPP: kev...@eecs.berkeley.edu
From fe2480277fa6e78db591fac3787a5779cb4a01f4 Mon Sep 17 00:00:00 2001
From: Kevin Zheng <kevinz5...@gmail.com>
Date: Mon, 9 Mar 2020 09:54:01 -0700
Subject: [PATCH 1/2] Retire MAX_OBJECTS

MAX_OBJECTS has probably outlived its usefulness. It was previously "no
hard limit," only serving to trigger map swapping immediately after
loading a map, if the number of used objects exceeded MAX_OBJECTS.

At worse case, MAX_OBJECTS causes an O(n^2) search and O(n) swaps, where
n is the number of maps in memory. This happens immediately after
loading a very large map. The server takes O(n) to search for the map
with the smallest remaining timeout and swaps it, and does this n times
or until enough memory is freed. If the other maps are small, this does
not free much memory and causes the "performance hit" mentioned in the
comments. This was observed on Invidious, where the server experienced
delays of up to 700 ms immediately after loading a large map due to
excessive swapping.

Removing MAX_OBJECTS does not significantly change the server's
allocation pattern because the server never frees memory (it maintains
an internal free list) and because maps are swapped out based on timeout
at the end of each tick anyway.
---
 include/config.h | 41 -------------------------------------
 include/sproto.h |  1 -
 server/c_misc.c  |  3 +--
 server/monster.c |  2 +-
 server/server.c  |  1 -
 server/swap.c    | 53 ------------------------------------------------
 6 files changed, 2 insertions(+), 99 deletions(-)

diff --git a/include/config.h b/include/config.h
index 4eb2ef92..7752c22a 100644
--- a/include/config.h
+++ b/include/config.h
@@ -336,8 +336,6 @@
  * DMFILE - file with dm/wizard access lists
  * LOGFILE - where to log if using -daemon option
  * MAP_ - various map timeout and swapping parameters
- * MAX_OBJECTS - how many objects to keep in memory.
- * MAX_OBJECTS_LWM - only swap maps out if below that value
  * MOTD - message of the day - printed each time someone joins the game
  * PERM_FILE - limit play times
  * SHUTDOWN - used when shutting down the server
@@ -427,45 +425,6 @@
 /** Default time to reset. */
 #define MAP_DEFAULTRESET       7200
 
-/**
- * MAX_OBJECTS is no hard limit.  If this limit is exceeded, Crossfire
- * will look for maps which are already scheldued for swapping, and
- * promptly swap them out before new maps are being loaded.
- * If playing only by yourself, this number can probably be as low as
- * 3000.  If in server mode, probably figure about 1000-2000 objects per
- * active player (if they typically play on different maps), for some guess
- * on how many to define.  If it is too low, maps just get swapped out
- * immediately, causing a performance hit.  If it is too high, the program
- * consumes more memory.  If you have gobs of free memory, a high number
- * might not be a bad idea.  Each object is around 656 bytes right now.
- * 100000 is about 63 MiB
- */
-#define MAX_OBJECTS     100000
-
-/**
- * Max objects low water mark (lwm).  If defined, the map swapping strategy
- * is a bit different:
- * 1) We only start swapping maps if the number of objects in use is
- *    greater than MAX_OBJECTS above.
- * 2) We keep swapping maps until there are no more maps to swap or the number
- *    of used objects drop below this low water mark value.
- *
- * If this is not defined, maps are swapped out on the timeout value above,
- * or if the number of objects used is greater than MAX_OBJECTS above.
- *
- * Note:  While this will prevent the pauses noticed when saving maps, there
- * can instead be cpu performance penalties - any objects in memory get
- * processed.  So if there are 4000 objects in memory, and 1000 of them
- * are living objects, the system will process all 1000 objects each tick.
- * With swapping enable, maybe 600 of the objects would have gotten swapped
- * out.  This is less likely a problem with a smaller number of MAX_OBJECTS
- * than if it is very large.
- * Also, the pauses you do get can be worse, as if you enter a map with
- * a lot of new objects and go above MAX_OBJECTS, it may have to swap out
- * many maps to get below the low water mark.
- */
-/*#define MAX_OBJECTS_LWM       MAX_OBJECTS/2*/
-
 /**
  * Defining MEMORY_DEBUG disables Crossfire's object allocator, which allocates
  * OBJ_EXPAND objects at a time and manages its own free list. It is faster at
diff --git a/include/sproto.h b/include/sproto.h
index 5aacf3c8..6eea26c1 100644
--- a/include/sproto.h
+++ b/include/sproto.h
@@ -581,7 +581,6 @@ void rod_adjust(object *rod);
 void read_map_log(void);
 int swap_map(mapstruct *map);
 void check_active_maps(void);
-void swap_below_max(const char *except_level);
 int players_on_map(mapstruct *m, int show_all);
 void flush_old_maps(void);
 /* time.c */
diff --git a/server/c_misc.c b/server/c_misc.c
index a117f8cb..130f5cda 100644
--- a/server/c_misc.c
+++ b/server/c_misc.c
@@ -237,8 +237,7 @@ static void malloc_info(object *op) {
                          i18n(op, "[fixed]Objects:"));
 
     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
-                         i18n(op, "[fixed]%6d used (%.2f%% of %d max)"),
-                         ob_used, (float)ob_used / MAX_OBJECTS * 100, MAX_OBJECTS);
+                         i18n(op, "[fixed]%6d used"), ob_used);
 
     if (ob_used != nrofallocobjects - nroffreeobjects) {
         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
diff --git a/server/monster.c b/server/monster.c
index 31a380e5..0ba4fab0 100644
--- a/server/monster.c
+++ b/server/monster.c
@@ -2207,7 +2207,7 @@ void monster_communicate(object *op, const char *txt) {
         FOR_MAP_PREPARE(mp, x, y, npc) {
             monster_talk_to_npc(npc, &info);
             if (orig_map != op->map) {
-                LOG(llevDebug, "Warning: Forced to swap out very recent map - MAX_OBJECTS should probably be increased\n");
+                LOG(llevDebug, "Warning: Forced to swap out very recent map\n");
                 return;
             }
         } FOR_MAP_FINISH();
diff --git a/server/server.c b/server/server.c
index 7b15f3a1..89b6bdfc 100644
--- a/server/server.c
+++ b/server/server.c
@@ -264,7 +264,6 @@ static void enter_map(object *op, mapstruct *newmap, int x, int y) {
                 set_map_timeout(oldmap);
         }
     }
-    swap_below_max(newmap->path);
 
     if (op->type == PLAYER) {
         map_newmap_cmd(&op->contr->socket);
diff --git a/server/swap.c b/server/swap.c
index a9ed0e2e..7c1b130e 100644
--- a/server/swap.c
+++ b/server/swap.c
@@ -195,66 +195,13 @@ void check_active_maps(void) {
         next = map->next;
         if (map->in_memory == MAP_IN_MEMORY && map->timeout != 0) {
             map->timeout -= 1;
-            /* If LWM is set, we only swap maps out when we run out of objects */
-#ifndef MAX_OBJECTS_LWM
             if (map->timeout == 0) {
                 swap_map(map);
             }
-#endif
         }
     }
 }
 
-/**
- * Returns the map with the lowest timeout variable (not 0).
- *
- * @param except_level
- * path of map to ignore for reset. Musn't be NULL.
- * @return
- * map, or NULL if no map is ready for reset.
- */
-static mapstruct *map_least_timeout(const char *except_level) {
-    mapstruct *map, *chosen = NULL;
-    int timeout = MAP_MAXTIMEOUT+1;
-
-    for (map = first_map; map != NULL; map = map->next)
-        if (map->in_memory == MAP_IN_MEMORY
-        && strcmp(map->path, except_level)
-        && map->timeout
-        && map->timeout < timeout)
-            chosen = map, timeout = map->timeout;
-    return chosen;
-}
-
-/**
- * Tries to swap out maps which are still in memory, because
- * of MAP_TIMEOUT until used objects is below MAX_OBJECTS or there are
- * no more maps to swap.
- *
- * @param except_level
- * path of map to ignore for reset. Musn't be NULL.
- */
-void swap_below_max(const char *except_level) {
-    mapstruct *map;
-
-    if (nrofallocobjects-nroffreeobjects < MAX_OBJECTS)
-        return;
-    for (;;) {
-#ifdef MAX_OBJECTS_LWM
-        if (nrofallocobjects-nroffreeobjects < MAX_OBJECTS_LWM)
-            return;
-#else
-        if (nrofallocobjects-nroffreeobjects < MAX_OBJECTS)
-            return;
-#endif
-        if ((map = map_least_timeout(except_level)) == NULL)
-            return;
-        LOG(llevDebug, "Trying to swap out %s before its time.\n", map->path);
-        map->timeout = 0;
-        swap_map(map);
-    }
-}
-
 /**
  * Returns the count of players on a map, calculated from player list.
  *
-- 
2.24.0

From 9fed1a2527c9fb400f95fe65cf49988a0b68d62e Mon Sep 17 00:00:00 2001
From: Kevin Zheng <kevinz5...@gmail.com>
Date: Mon, 9 Mar 2020 11:22:58 -0700
Subject: [PATCH 2/2] Retire object allocator

The object allocator allocates OBJ_EXPAND objects at a time and manages
its own free list. It is faster at allocating many objects at once, but
defeats memory debuggers and mitigation techniques. It also does not
return unused memory to the operating system.

Rewrite object_new() to always allocate memory using calloc(). This will
incur some memory overhead since an object struct does not fit perfectly
into a nice allocator slab size.

object_free2() adds freed objects to a free list that is reclaimed at
the end of each server tick. It cannot immediately free object memory,
because some callers expect to be able to query it for FLAG_FREED to
detect object removal.
---
 common/object.c  | 133 ++++++++---------------------------------------
 include/config.h |  15 ------
 include/object.h |   4 +-
 server/c_misc.c  |  19 +------
 server/server.c  |   1 +
 5 files changed, 29 insertions(+), 143 deletions(-)

diff --git a/common/object.c b/common/object.c
index dab30909..7a465eb7 100644
--- a/common/object.c
+++ b/common/object.c
@@ -41,21 +41,12 @@
 
 static int compare_ob_value_lists_one(const object *, const object *);
 static int compare_ob_value_lists(const object *, const object *);
-static void expand_objects(void);
 static void permute(int *, int, int);
 static int object_set_value_s(object *, const char *, const char *, int);
 static void object_increase_nrof(object *op, uint32_t i);
 
-#ifdef MEMORY_DEBUG
-int nroffreeobjects = 0;  /**< Number of free objects. */
 int nrofallocobjects = 0; /**< Number of allocated objects. */
-#undef OBJ_EXPAND
-#define OBJ_EXPAND 1
-#else
-static object objarray[STARTMAX]; /**< All objects, allocated this way at first */
-int nroffreeobjects = STARTMAX;  /**< How many OBs allocated and free (free) */
-int nrofallocobjects = STARTMAX; /**< How many OBs allocated (free + used) */
-#endif
+int nrofallocobjects_peak = 0; //< Peak number of allocated objects
 
 object *objects;           /**< Pointer to the list of used objects */
 static object *free_objects;      /**< Pointer to the list of unused objects */
@@ -94,26 +85,7 @@ void init_objects(void) {
     /* Initialize all objects: */
     objects = NULL;
     active_objects = NULL;
-
-#ifdef MEMORY_DEBUG
     free_objects = NULL;
-#else
-    free_objects = objarray;
-    objarray[0].prev = NULL,
-    objarray[0].next = &objarray[1],
-    SET_FLAG(&objarray[0], FLAG_REMOVED);
-    SET_FLAG(&objarray[0], FLAG_FREED);
-    for (int i = 1; i < STARTMAX-1; i++) {
-        objarray[i].next = &objarray[i+1];
-        objarray[i].prev = &objarray[i-1];
-        SET_FLAG(&objarray[i], FLAG_REMOVED);
-        SET_FLAG(&objarray[i], FLAG_FREED);
-    }
-    objarray[STARTMAX-1].next = NULL;
-    objarray[STARTMAX-1].prev = &objarray[STARTMAX-2];
-    SET_FLAG(&objarray[STARTMAX-1], FLAG_REMOVED);
-    SET_FLAG(&objarray[STARTMAX-1], FLAG_FREED);
-#endif
 }
 
 /**
@@ -538,6 +510,17 @@ object *object_find_by_name_global(const char *str) {
     return op;
 }
 
+void object_free_freelist(void) {
+    object *op, *next;
+    for (op = free_objects; op != NULL; ) {
+        next = op->next;
+        free(op);
+        nrofallocobjects--;
+        op = next;
+    }
+    free_objects = NULL;
+}
+
 /**
  * Destroys all allocated objects.
  *
@@ -551,18 +534,8 @@ object *object_find_by_name_global(const char *str) {
  * free_all_object_data() has been renamed to object_free_object_data()
  */
 void object_free_all_data(void) {
-#ifdef MEMORY_DEBUG
+    object_free_freelist();
     object *op, *next;
-
-    for (op = free_objects; op != NULL; ) {
-        next = op->next;
-        free(op);
-        nrofallocobjects--;
-        nroffreeobjects--;
-        op = next;
-    }
-    free_objects = NULL;
-
     for (op = objects; op != NULL; ) {
         next = op->next;
         if (!QUERY_FLAG(op, FLAG_FREED)) {
@@ -570,9 +543,8 @@ void object_free_all_data(void) {
         }
         op = next;
     }
-#endif
 
-    LOG(llevDebug, "%d allocated objects, %d free objects, STARMAX=%d\n", nrofallocobjects, nroffreeobjects, STARTMAX);
+    LOG(llevDebug, "%d allocated objects\n", nrofallocobjects);
 }
 
 /**
@@ -1015,83 +987,27 @@ void object_copy_with_inv(const object *src_ob, object *dest_ob) {
 }
 
 /**
- * Allocates more objects for the list of unused objects.
- *
- * It is called from object_new() if the unused list is empty.
- *
- * If there is not enough memory, fatal() is called.
- */
-static void expand_objects(void) {
-    int i;
-    object *new;
-
-    new = (object *)CALLOC(OBJ_EXPAND, sizeof(object));
-
-    if (new == NULL)
-        fatal(OUT_OF_MEMORY);
-    free_objects = new;
-    new[0].prev = NULL;
-    new[0].next = &new[1],
-    SET_FLAG(&new[0], FLAG_REMOVED);
-    SET_FLAG(&new[0], FLAG_FREED);
-
-    for (i = 1; i < OBJ_EXPAND-1; i++) {
-        new[i].next = &new[i+1],
-        new[i].prev = &new[i-1],
-        SET_FLAG(&new[i], FLAG_REMOVED);
-        SET_FLAG(&new[i], FLAG_FREED);
-    }
-    new[OBJ_EXPAND-1].prev = &new[OBJ_EXPAND-2],
-    new[OBJ_EXPAND-1].next = NULL,
-    SET_FLAG(&new[OBJ_EXPAND-1], FLAG_REMOVED);
-    SET_FLAG(&new[OBJ_EXPAND-1], FLAG_FREED);
-
-    nrofallocobjects += OBJ_EXPAND;
-    nroffreeobjects += OBJ_EXPAND;
-}
-
-/**
- * Grabs an object from the list of unused objects, makes
- * sure it is initialised, and returns it.
- *
- * If there are no free objects, expand_objects() is called to get more.
+ * Allocate an object, makes sure it is initialised, and returns it.
  *
  * @return
  * cleared and ready to use object*.
  *
  * @note
- * will never fail, as expand_objects() will fatal() if memory allocation error.
+ * will never fail, as will fatal() if memory allocation error.
  *
  * @note
  * get_object() has been renamed to object_new()
  */
 object *object_new(void) {
     object *op;
-#ifdef MEMORY_DEBUG
-    /* FIXME: However this doesn't work since object_free2() sometimes add
-     * objects back to the free_objects linked list, and some functions mess
-     * with the object after return of object_free2(). This is bad and should be
-     * fixed. But it would need fairly extensive changes and a lot of debugging.
-     */
     op = calloc(1, sizeof(object));
-    if (op == NULL)
+    if (op == NULL) {
         fatal(OUT_OF_MEMORY);
-#else
-    if (free_objects == NULL) {
-        expand_objects();
     }
-    op = free_objects;
-    if (!QUERY_FLAG(op, FLAG_FREED)) {
-        LOG(llevError, "Fatal: Getting busy object.\n");
-#ifdef MANY_CORES
-        abort();
-#endif
+    nrofallocobjects++;
+    if (nrofallocobjects > nrofallocobjects_peak) {
+        nrofallocobjects_peak = nrofallocobjects;
     }
-    free_objects = op->next;
-    if (free_objects != NULL)
-        free_objects->prev = NULL;
-    nroffreeobjects--;
-#endif
     op->count = ++ob_count;
     op->name = NULL;
     op->name_pl = NULL;
@@ -1550,17 +1466,14 @@ void object_free2(object *ob, int flags) {
         }
     }
 
-#ifdef MEMORY_DEBUG
-    free(ob);
-#else
-    /* Now link it with the free_objects list: */
+    /* Now link it with the free_objects list for reclaimation at end of tick.
+     * This allows the server to briefly use the object after "free" to check
+     * for FLAG_REMOVED */
     ob->prev = NULL;
     ob->next = free_objects;
     if (free_objects != NULL)
         free_objects->prev = ob;
     free_objects = ob;
-    nroffreeobjects++;
-#endif
 }
 
 /**
diff --git a/include/config.h b/include/config.h
index 7752c22a..3461308f 100644
--- a/include/config.h
+++ b/include/config.h
@@ -425,19 +425,6 @@
 /** Default time to reset. */
 #define MAP_DEFAULTRESET       7200
 
-/**
- * Defining MEMORY_DEBUG disables Crossfire's object allocator, which allocates
- * OBJ_EXPAND objects at a time and manages its own free list. It is faster at
- * allocating lots of objects, but defeats memory debuggers and mitigation
- * techniques by managing its own allocations and enabling use-after-free bugs.
- *
- * Unfortunately, much of the code does not work without use-after-free because
- * even checking if an object was freed requires looking in the object. Until
- * these issues are fixed, Crossfire needs MEMORY_DEBUG unset in order to run
- * without crashing frequently.
- */
-/*#define MEMORY_DEBUG*/
-
 /**
  * If you want to have a Message Of The Day file, define MOTD to be
  * the file with the message.  If the file doesn't exist or if it
@@ -520,8 +507,6 @@
 #define BANISHFILE      "banish_file"
 
 #define MAX_ERRORS      25      /**< Bail out if more are received during tick. */
-#define STARTMAX        500     /**< How big array of objects to start with. */
-#define OBJ_EXPAND      100     /**< How big steps to use when expanding array. */
 
 #define HIGHSCORE_LENGTH 1000   /**< How many entries there are room for. */
 
diff --git a/include/object.h b/include/object.h
index a03b0206..9c4fa999 100644
--- a/include/object.h
+++ b/include/object.h
@@ -477,7 +477,7 @@ extern object *objects;
 extern object *active_objects;
 
 extern int nrofallocobjects;
-extern int nroffreeobjects;
+extern int nrofallocobjects_peak;
 
 static inline int compare_flags(const object *p, const object *q) {
     return ((p)->flags[0] == (q)->flags[0]) &&
@@ -601,4 +601,6 @@ static inline bool CAN_PROBE(const object *ob) {
         (ob->type == PLAYER || QUERY_FLAG(ob, FLAG_MONSTER));
 }
 
+void object_free_freelist(void);
+
 #endif /* OBJECT_H */
diff --git a/server/c_misc.c b/server/c_misc.c
index 130f5cda..37eba354 100644
--- a/server/c_misc.c
+++ b/server/c_misc.c
@@ -237,23 +237,8 @@ static void malloc_info(object *op) {
                          i18n(op, "[fixed]Objects:"));
 
     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
-                         i18n(op, "[fixed]%6d used"), ob_used);
-
-    if (ob_used != nrofallocobjects - nroffreeobjects) {
-        draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
-                             i18n(op, "[fixed]      (used list mismatch: %d)"),
-                             nrofallocobjects - nroffreeobjects);
-    }
-
-    draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
-                         i18n(op, "[fixed]%6d free (%.2f%% of %d allocated)"),
-                         ob_free, (float)ob_free / nrofallocobjects * 100, nrofallocobjects);
-
-    if (ob_free != nroffreeobjects) {
-        draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
-                             i18n(op, "[fixed]      (free list mismatch: %d)"),
-                             nroffreeobjects);
-    }
+                         i18n(op, "[fixed]%6d used (%d peak), %d laundry (of %d allocated)"),
+                         ob_used, nrofallocobjects_peak, ob_free, nrofallocobjects);
 
     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_MALLOC,
                          i18n(op, "[fixed]%6d on active list"),
diff --git a/server/server.c b/server/server.c
index 89b6bdfc..efa9fee6 100644
--- a/server/server.c
+++ b/server/server.c
@@ -1456,6 +1456,7 @@ void server_main(int argc, char *argv[]) {
         check_active_maps(); /* Removes unused maps after a certain timeout */
         do_specials();       /* Routines called from time to time. */
         update_players();
+        object_free_freelist();
     }
 
     /* This is unreachable. */
-- 
2.24.0

___ Begin jemalloc statistics ___
Version: "5.1.0-0-g61efbda7098de6fe64c362d309824864308c36d4"
Build-time option settings
  config.cache_oblivious: true
  config.debug: false
  config.fill: true
  config.lazy_lock: true
  config.malloc_conf: "abort_conf:false"
  config.prof: false
  config.prof_libgcc: false
  config.prof_libunwind: false
  config.stats: true
  config.utrace: true
  config.xmalloc: true
Run-time option settings
  opt.abort: false
  opt.abort_conf: false
  opt.retain: false
  opt.dss: "secondary"
  opt.narenas: 16
  opt.percpu_arena: "disabled"
  opt.metadata_thp: "disabled"
  opt.dirty_decay_ms: 10000 (arenas.dirty_decay_ms: 10000)
  opt.muzzy_decay_ms: 10000 (arenas.muzzy_decay_ms: 10000)
  opt.junk: "false"
  opt.zero: false
  opt.utrace: false
  opt.xmalloc: false
  opt.tcache: true
  opt.lg_tcache_max: 15
  opt.thp: "not supported"
  opt.stats_print: true
  opt.stats_print_opts: ""
Arenas: 16
Quantum size: 16
Page size: 4096
Maximum thread-cached size class: 32768
Number of bin size classes: 36
Number of thread-cache bin size classes: 41
Number of large size classes: 196
Allocated: 15677408, active: 17059840, metadata: 3074680 (n_thp 0), resident: 36777984, mapped: 40017920, retained: 0
Background threads: 0, num_runs: 0, run_interval: 0 ns
                           n_lock_ops       n_waiting      n_spin_acq  n_owner_switch   total_wait_ns     max_wait_ns  max_n_thds
background_thread                   0               0               0               0               0               0           0
ctl                                 0               0               0               0               0               0           0
prof                                0               0               0               0               0               0           0
arenas[0]:
assigned threads: 1
uptime: 173942476214
dss allocation precedence: "disabled"
decaying:  time       npages       sweeps     madvises       purged
   dirty: 10000         3987           34          590         8930
   muzzy: 10000           82           29          440         6816
                            allocated     nmalloc     ndalloc   nrequests
small:                       14211040      290027      244418      488249
large:                        1466368         136         122         136
total:                       15677408      290163      244540      488385
                                     
active:                      17059840
mapped:                      40017920
retained:                           0
base:                         3046000
internal:                       28680
metadata_thp:                       0
tcache_bytes:                  370512
resident:                    36777984
                           n_lock_ops       n_waiting      n_spin_acq  n_owner_switch   total_wait_ns     max_wait_ns  max_n_thds
large                               0               0               0               0               0               0           0
extent_avail                        0               0               0               0               0               0           0
extents_dirty                       0               0               0               0               0               0           0
extents_muzzy                       0               0               0               0               0               0           0
extents_retained                    0               0               0               0               0               0           0
decay_dirty                         0               0               0               0               0               0           0
decay_muzzy                         0               0               0               0               0               0           0
base                                0               0               0               0               0               0           0
tcache_list                         0               0               0               0               0               0           0
bins:           size ind    allocated      nmalloc      ndalloc    nrequests      curregs     curslabs regs pgs   util       nfills     nflushes       nslabs     nreslabs      n_lock_ops       n_waiting      n_spin_acq  n_owner_switch   total_wait_ns     max_wait_ns  max_n_thds
                   8   0        13888         1832           96         3344         1736            4  512   1  0.847           74           21            4            0               0               0               0               0               0               0           0
                  16   1       112736         7226          180         9847         7046           28  256   1  0.982          149           39           28            0               0               0               0               0               0               0           0
                  32   2       131840       112502       108382       202364         4120           58  128   1  0.554         8325         1112          760          202               0               0               0               0               0               0           0
                  48   3       378336        34220        26338        36015         7882           58  256   3  0.530         4948          299           78          219               0               0               0               0               0               0           0
                  64   4       163264         4907         2356         8682         2551           42   64   1  0.949          174           81           73           14               0               0               0               0               0               0           0
                  80   5       241920         3226          202         6190         3024           12  256   5  0.984           66           40           13            1               0               0               0               0               0               0           0
                  96   6        42240          554          114         2767          440            4  128   3  0.859           18           24            5            1               0               0               0               0               0               0           0
                 112   7         6048          190          136           83           54            1  256   7  0.210            9           15            1            0               0               0               0               0               0               0           0
                 128   8        14080          158           48          201          110            4   32   1  0.859           15           14            5            1               0               0               0               0               0               0           0
                 160   9       127680          954          156          882          798            7  128   5  0.890           38           17            7            0               0               0               0               0               0               0           0
                 192  10       232704         1300           88         1233         1212           19   64   3  0.996           30            9           21            2               0               0               0               0               0               0           0
                 224  11       213696         1086          132         1033          954            8  128   7  0.931           40           14            8            0               0               0               0               0               0               0           0
                 256  12       196096          824           58        83864          766           48   16   1  0.997          100           29           52            5               0               0               0               0               0               0           0
                 320  13       358720         1200           79         1179         1121           18   64   5  0.973           36           11           18            0               0               0               0               0               0               0           0
                 384  14       361344         1020           79          992          941           30   32   3  0.980           57            7           31            1               0               0               0               0               0               0           0
                 448  15       254912          698          129          623          569            9   64   7  0.987           40           11           11            2               0               0               0               0               0               0           0
                 512  16       172032          349           13          393          336           43    8   1  0.976           38            5           44            6               0               0               0               0               0               0           0
                 640  17       275200          631          201         4217          430           15   32   5  0.895           47           33           19            4               0               0               0               0               0               0           0
                 768  18      7500288       114852       105086       117075         9766          656   16   3  0.930        19728         6589         6811         1177               0               0               0               0               0               0           0
                 896  19       159488          236           58          223          178            6   32   7  0.927           29           14            6            0               0               0               0               0               0               0           0
                1024  20       440320          480           50          484          430          108    4   1  0.995          145           29          121            7               0               0               0               0               0               0           0
                1280  21       398080          393           82         3796          311           21   16   5  0.925          115           35           22            4               0               0               0               0               0               0           0
                1536  22       296448          215           22          223          193           25    8   3  0.965           53            7           27            2               0               0               0               0               0               0           0
                1792  23       250880          166           26          158          140            9   16   7  0.972           23           10            9            0               0               0               0               0               0               0           0
                2048  24       165888          107           26           97           81           41    2   1  0.987           45            8           54            2               0               0               0               0               0               0           0
                2560  25       258560          119           18          114          101           13    8   5  0.971           56            7           16            1               0               0               0               0               0               0           0
                3072  26       479232          194           38          210          156           44    4   3  0.886           71            8           49            5               0               0               0               0               0               0           0
                3584  27        60928           57           40         1569           17            3    8   7  0.708           32           27            5            0               0               0               0               0               0               0           0
                4096  28       135168           70           37          181           33           33    1   1      1           20           17           70            0               0               0               0               0               0               0           0
                5120  29       322560          105           42           71           63           16    4   5  0.984           22           18           25            4               0               0               0               0               0               0           0
                6144  30       104448           31           14           25           17            9    2   3  0.944            6            6           15            3               0               0               0               0               0               0           0
                7168  31        43008           28           22           18            6            2    4   7  0.750            9            9            9            3               0               0               0               0               0               0           0
                8192  32        57344           20           13           19            7            7    1   2      1            6            5           20            0               0               0               0               0               0               0           0
               10240  33        20480           19           17           30            2            1    2   5      1            4            5           10            0               0               0               0               0               0               0           0
               12288  34       221184           42           24           33           18           18    1   3      1            8            7           42            0               0               0               0               0               0               0           0
               14336  35            0           16           16           14            0            0    2   7      1            6            7            9            0               0               0               0               0               0               0           0
large:          size ind    allocated      nmalloc      ndalloc    nrequests  curlextents
               16384  36        16384            4            3            9            1
               20480  37        20480            6            5           61            1
               24576  38        49152            4            2            5            2
               28672  39        86016            7            4           10            3
                     ---
               40960  41            0           19           19           19            0
               49152  42            0           10           10           10            0
               57344  43            0            3            3            3            0
               65536  44            0            3            3            3            0
               81920  45            0            4            4            4            0
               98304  46        98304            5            4            5            1
              114688  47       344064           19           16           19            3
              131072  48            0           22           22           22            0
                     ---
              196608  50       196608            3            2            3            1
              229376  51            0            1            1            1            0
                     ---
              327680  53       655360           25           23           25            2
                     ---
              458752  55            0            1            1            1            0
                     ---
--- End jemalloc statistics ---
_______________________________________________
crossfire mailing list
crossfire@metalforge.org
http://mailman.metalforge.org/mailman/listinfo/crossfire

Reply via email to