diff --git a/include/salloc.h b/include/salloc.h
index fe43308f9d843b36d7be71ca1b001a9058e12b59..773bdd08719d5938ff002774a650a4d050e33efd 100644
--- a/include/salloc.h
+++ b/include/salloc.h
@@ -38,10 +38,9 @@ bool salloc_init(size_t size, size_t minimal, double factor);
 void salloc_free(void);
 void *salloc(size_t size, const char *what);
 void sfree(void *ptr);
+void sfree_delayed(void *ptr);
 void slab_validate();
-
 void salloc_protect(void);
-void salloc_batch_mode(bool mode);
 
 /** Statistics on utilization of a single slab class. */
 struct slab_cache_stats {
diff --git a/src/box/space.cc b/src/box/space.cc
index d9c255010411abbeb9b31634804c152533b49948..3ee39e0ca830d689371baf277ce7dc96b1b48d9a 100644
--- a/src/box/space.cc
+++ b/src/box/space.cc
@@ -216,7 +216,7 @@ space_free(void)
 				mh_i32ptr_node(spaces, i)->val;
 		space_delete(space);
 	}
-	tuple_free();
+	tuple_format_free();
 }
 
 
@@ -265,7 +265,7 @@ void
 space_init(void)
 {
 	spaces = mh_i32ptr_new();
-	tuple_init();
+	tuple_format_init();
 
 	/* configure regular spaces */
 	space_config();
diff --git a/src/box/tuple.cc b/src/box/tuple.cc
index 0daec173676555e64ebe8618fb1fc20d6ed4bd7b..94e3472df7ba4eee2223075fe42ea0bccd36f974 100644
--- a/src/box/tuple.cc
+++ b/src/box/tuple.cc
@@ -203,6 +203,8 @@ tuple_init_field_map(struct tuple *tuple, struct tuple_format *format)
 	}
 }
 
+extern uint32_t snapshot_version;
+
 /** Allocate a tuple */
 struct tuple *
 tuple_alloc(struct tuple_format *format, size_t size)
@@ -212,6 +214,7 @@ tuple_alloc(struct tuple_format *format, size_t size)
 	struct tuple *tuple = (struct tuple *)(ptr + format->field_map_size);
 
 	tuple->refs = 0;
+	tuple->version = snapshot_version;
 	tuple->bsize = size;
 	tuple->format_id = tuple_format_id(format);
 
@@ -229,7 +232,10 @@ tuple_free(struct tuple *tuple)
 	say_debug("tuple_free(%p)", tuple);
 	assert(tuple->refs == 0);
 	char *ptr = (char *) tuple - tuple_format(tuple)->field_map_size;
-	sfree(ptr);
+	if (tuple->version == snapshot_version)
+		sfree(ptr);
+	else
+		sfree_delayed(ptr);
 }
 
 /**
@@ -510,13 +516,13 @@ tuple_compare_with_key(const struct tuple *tuple, const char *key,
 }
 
 void
-tuple_init()
+tuple_format_init()
 {
 	tuple_format_ber = tuple_format_new(NULL, 0);
 }
 
 void
-tuple_free()
+tuple_format_free()
 {
 	for (struct tuple_format **format = tuple_formats;
 	     format < tuple_formats + formats_size;
diff --git a/src/box/tuple.h b/src/box/tuple.h
index bd893244c2040773087d8a61e09f1f2f5e2a796e..9b663cbb01a2aa17ba3fc46fe9428bf720658dff 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -115,6 +115,8 @@ tuple_format_new(struct key_def *key_def, uint32_t key_count);
  */
 struct tuple
 {
+	/** snapshot generation version */
+	uint32_t version;
 	/** reference counter */
 	uint16_t refs;
 	/** format identifier */
@@ -370,10 +372,10 @@ tuple_to_luabuf(struct tuple *tuple, struct luaL_Buffer *b);
 
 /** Initialize tuple library */
 void
-tuple_init();
+tuple_format_init();
 
 /** Cleanup tuple library */
 void
-tuple_free();
+tuple_format_free();
 #endif /* TARANTOOL_BOX_TUPLE_H_INCLUDED */
 
diff --git a/src/salloc.cc b/src/salloc.cc
index 0a66d1d85faf7cc5c1cd10c707e07ac021cfe65d..da14adb48a4a3f91caa01a9be6f461775b7717df 100644
--- a/src/salloc.cc
+++ b/src/salloc.cc
@@ -40,7 +40,6 @@
 #include <third_party/queue.h>
 #include "tarantool/util.h"
 #include <tbuf.h>
-#include <qbuf.h>
 #include <say.h>
 #include "exception.h"
 
@@ -62,14 +61,16 @@ static const size_t MAX_SLAB_ITEM = 1 << 20;
 size_t MAX_SLAB_ITEM_COUNT;
 
 struct slab_item {
-	struct slab_item *next;
+    SLIST_ENTRY(slab_item) next;
 };
 
+SLIST_HEAD(item_slist_head, slab_item);
+
 struct slab {
 	uint32_t magic;
 	size_t used;
 	size_t items;
-	struct slab_item *free;
+	struct item_slist_head free;
 	struct slab_cache *cache;
 	void *brk;
 	SLIST_ENTRY(slab) link;
@@ -89,9 +90,8 @@ struct slab_cache {
 struct arena {
 	void *mmap_base;
 	size_t mmap_size;
-	bool delayed_free_mode;
+	int64_t delayed_free_count;
 	size_t delayed_free_batch;
-	struct qbuf delayed_q;
 	void *base;
 	size_t size;
 	size_t used;
@@ -99,6 +99,7 @@ struct arena {
 };
 
 static uint32_t slab_active_caches;
+static struct item_slist_head free_delayed;
 static struct slab_cache slab_caches[256];
 static struct arena arena;
 
@@ -129,17 +130,15 @@ slab_caches_init(size_t minimal, double factor)
 
 	MAX_SLAB_ITEM_COUNT = (size_t) (SLAB_SIZE - sizeof(struct slab)) /
 			slab_caches[0].item_size;
+
+	SLIST_INIT(&free_delayed);
 }
 
 static bool
 arena_init(struct arena *arena, size_t size)
 {
-	arena->delayed_free_mode = false;
 	arena->delayed_free_batch = 100;
-
-	int rc = qbuf_init(&arena->delayed_q, 4096);
-	if (rc == -1)
-		return false;
+	arena->delayed_free_count = 0;
 
 	arena->used = 0;
 	arena->size = size - size % SLAB_SIZE;
@@ -149,7 +148,6 @@ arena_init(struct arena *arena, size_t size)
 				PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 	if (arena->mmap_base == MAP_FAILED) {
 		say_syserror("mmap");
-		qbuf_free(&arena->delayed_q);
 		return false;
 	}
 
@@ -164,10 +162,6 @@ void salloc_protect(void) {
 	mprotect(arena.mmap_base, arena.mmap_size, PROT_READ);
 }
 
-void salloc_batch_mode(bool mode) {
-	arena.delayed_free_mode = mode;
-}
-
 static void *
 arena_alloc(struct arena *arena)
 {
@@ -201,7 +195,6 @@ salloc_free(void)
 {
 	if (arena.mmap_base != NULL)
 		munmap(arena.mmap_base, arena.mmap_size);
-	qbuf_free(&arena.delayed_q);
 	memset(&arena, 0, sizeof(struct arena));
 }
 
@@ -211,7 +204,7 @@ format_slab(struct slab_cache *cache, struct slab *slab)
 	assert(cache->item_size <= MAX_SLAB_ITEM);
 
 	slab->magic = SLAB_MAGIC;
-	slab->free = NULL;
+	SLIST_INIT(&slab->free);
 	slab->cache = cache;
 	slab->items = 0;
 	slab->used = 0;
@@ -288,21 +281,20 @@ valid_item(struct slab *slab, void *item)
 }
 #endif
 
-static void
-sfree_do(void *ptr)
+void
+sfree(void *ptr)
 {
 	struct slab *slab = slab_header(ptr);
 	struct slab_cache *cache = slab->cache;
 	struct slab_item *item = (struct slab_item *) ptr;
 
-	if (fully_formatted(slab) && slab->free == NULL)
+	if (fully_formatted(slab) && SLIST_EMPTY(&slab->free))
 		TAILQ_INSERT_TAIL(&cache->free_slabs, slab, cache_free_link);
 
 	assert(valid_item(slab, item));
-	assert(slab->free == NULL || valid_item(slab, slab->free));
+	assert(SLIST_EMPTY(&slab->free) || valid_item(slab, SLIST_FIRST(&slab->free)));
 
-	item->next = slab->free;
-	slab->free = item;
+	SLIST_INSERT_HEAD(&slab->free, item, next);
 	slab->used -= cache->item_size + sizeof(red_zone);
 	slab->items -= 1;
 
@@ -319,26 +311,26 @@ static void
 sfree_batch(void)
 {
 	ssize_t batch = arena.delayed_free_batch;
-	size_t n = qbuf_n(&arena.delayed_q);
-	while (batch-- > 0 && n-- > 0) {
-		void *ptr = qbuf_pop(&arena.delayed_q);
-		assert(ptr != NULL);
-		sfree_do(ptr);
+
+	while (--batch >= 0 && !SLIST_EMPTY(&free_delayed)) {
+		assert(arena.delayed_free_count > 0);
+		struct slab_item *item = SLIST_FIRST(&free_delayed);
+		SLIST_REMOVE_HEAD(&free_delayed, next);
+		arena.delayed_free_count--;
+		sfree(item);
 	}
 }
 
 void
-sfree(void *ptr)
+sfree_delayed(void *ptr)
 {
 	if (ptr == NULL)
 		return;
-	if (arena.delayed_free_mode) {
-		if (qbuf_push(&arena.delayed_q, ptr) == -1)
-			panic("failed to add tuple to the delayed queue");
-		return;
-	}
-	sfree_batch();
-	return sfree_do(ptr);
+	struct slab_item *item = (struct slab_item *)ptr;
+	struct slab *slab = slab_header(item);
+	assert(valid_item(slab, item));
+	SLIST_INSERT_HEAD(&free_delayed, item, next);
+	arena.delayed_free_count++;
 }
 
 void *
@@ -348,8 +340,7 @@ salloc(size_t size, const char *what)
 	struct slab *slab;
 	struct slab_item *item;
 
-	if (! arena.delayed_free_mode)
-		sfree_batch();
+	sfree_batch();
 
 	if ((cache = cache_for(size)) == NULL ||
 	    (slab = slab_of(cache)) == NULL) {
@@ -358,21 +349,20 @@ salloc(size_t size, const char *what)
 			  "slab allocator", what);
 	}
 
-	if (slab->free == NULL) {
+	if (SLIST_EMPTY(&slab->free)) {
 		assert(valid_item(slab, slab->brk));
 		item = (struct slab_item *) slab->brk;
 		memcpy((char *)item + cache->item_size, red_zone, sizeof(red_zone));
 		slab->brk = (char *) slab->brk + cache->item_size + sizeof(red_zone);
 	} else {
-		assert(valid_item(slab, slab->free));
-		item = slab->free;
-
+		item = SLIST_FIRST(&slab->free);
+		assert(valid_item(slab, item));
 		(void) VALGRIND_MAKE_MEM_DEFINED(item, sizeof(void *));
-		slab->free = item->next;
+		SLIST_REMOVE_HEAD(&slab->free, next);
 		(void) VALGRIND_MAKE_MEM_UNDEFINED(item, sizeof(void *));
 	}
 
-	if (fully_formatted(slab) && slab->free == NULL)
+	if (fully_formatted(slab) && SLIST_EMPTY(&slab->free))
 		TAILQ_REMOVE(&cache->free_slabs, slab, cache_free_link);
 
 	slab->used += cache->item_size + sizeof(red_zone);
diff --git a/src/tarantool.cc b/src/tarantool.cc
index 0954edb2c81e9a1566631d654dd6cbfa33a1bec5..bc68749f49f5940ff8320ab3e7269a5b7d76db43 100644
--- a/src/tarantool.cc
+++ b/src/tarantool.cc
@@ -84,6 +84,8 @@ struct tarantool_cfg cfg;
 static ev_signal *sigs = NULL;
 
 int snapshot_pid = 0; /* snapshot processes pid */
+uint32_t snapshot_version = 0;
+
 extern const void *opt_def;
 
 static int
@@ -328,7 +330,8 @@ snapshot(void)
 	if (snapshot_pid)
 		return EINPROGRESS;
 
-	salloc_batch_mode(true);
+	/* increment snapshot version */
+	snapshot_version++;
 
 	pid_t p = fork();
 	if (p < 0) {
@@ -340,7 +343,6 @@ snapshot(void)
 		say_warn("waiting for dumper %d", p);
 		int status = wait_for_child(p);
 		say_warn("dumper finished %d", p);
-		salloc_batch_mode(true);
 		snapshot_pid = 0;
 		return (WIFSIGNALED(status) ? EINTR : WEXITSTATUS(status));
 	}