diff --git a/core/tarantool_lua.m b/core/tarantool_lua.m
index c5dde48b60e1c29d5f503bc084fe4f4a93739388..1ed40a189688d56670e64c6580427b3053825852 100644
--- a/core/tarantool_lua.m
+++ b/core/tarantool_lua.m
@@ -207,30 +207,30 @@ static const struct luaL_reg boxlib[] = {
 /** {{{ box.fiber Lua library: access to Tarantool/Box fibers
  *
  * Each fiber can be running, suspended or dead.
- * It can also be attached or detached.
- * All fibers are part of the fiber registry,
- * box.fiber. This registry can be searched either by
+ * A fiber is created (box.fiber.create()) suspended.
+ * It can be started with box.fiber.resume(), yield
+ * the control back with box.fiber.yield() end
+ * with return or just by reaching the end of the
+ * function.
+ *
+ * A fiber can also be attached or detached.
+ * An attached fiber is a child of the creator,
+ * and is running only if the creator has called
+ * box.fiber.resume(). A detached fiber is a child of
+ * Tarntool/Box internal 'sched' fiber, and is gets
+ * scheduled only if there is a libev event associated
+ * with it.
+ * To detach, a running fiber must invoke box.fiber.detach().
+ * A detached fiber loses connection with its parent
+ * forever.
+ *
+ * All fibers are part of the fiber registry, box.fiber.
+ * This registry can be searched either by
  * fiber id (fid), which is numeric, or by fiber name,
  * which is a string. If there is more than one
  * fiber with the given name, the first fiber that
  * matches is returned.
  *
- * A new fiber can also be created from Lua, with
- * fiber.create(). The fiber
- * is created suspended, and is thus "attached"
- * to the creator. The creator can invoke the suspended
- * fiber with fiber.resume(), and the invoked fiber
- * can yield control back to the caller with fiber.yield().
- *
- * An active fiber, however, may choose to "detach"
- * from the caller, and become part of the main Tarantool/Box
- * loop. This is what all internal Tarantool/Box fibers
- * are -- detached. To "detach" from its creator,
- * a running fiber can use fiber.detach(). A detached
- * fiber becomes attached to the internal "sched"
- * fiber, and can not be attached back to its original
- * creator.
- *
  * Once fiber chunk is done or calls "return",
  * the fiber is considered dead. Its carcass is put into
  * fiber pool, and can be reused when another fiber is
@@ -241,20 +241,73 @@ static const struct luaL_reg boxlib[] = {
  * only if the runaway fiber is calling fiber.testcancel()
  * once in a while. Most box.* hooks, such as box.delete()
  * or box.update(), are calling fiber.testcancel().
+ *
  * Thus a runaway fiber can really only become cuckoo
  * if it does a lot of computations and doesn't check
  * whether it's been cancelled (just don't do that).
+ *
+ * The other potential problem comes from detached
+ * fibers which never get scheduled, because are subscribed
+ * or get no events. Such morphing fibers can be killed
+ * with box.fiber.cancel(), since box.fiber.cancel()
+ * sends an asynchronous wakeup event to the fiber.
  */
 
 static const char *fiberlib_name = "box.fiber";
 
-struct fiber *
+/** Push a userdata for the given fiber onto Lua stack. */
+static void
+lbox_pushfiber(struct lua_State *L, struct fiber *f)
+{
+	/*
+	 * Use 'memoize'  pattern and keep a single userdata for
+	 * the given fiber.
+	 */
+	luaL_getmetatable(L, fiberlib_name);
+	int top = lua_gettop(L);
+	lua_getfield(L, -1, "memoize");
+	if (lua_isnil(L, -1)) { /* first access - instantiate memoize */
+		lua_pop(L, 1);                  /* pop the nil */
+		lua_newtable(L);                /* create memoize table */
+		lua_newtable(L);                /* and a metatable */
+		lua_pushstring(L, "kv"); /* weak keys and values */
+		lua_setfield(L, -2, "__mode"); /* pops 'kv' */
+		lua_setmetatable(L, -2); /* pops the metatable */
+		lua_setfield(L, -2, "memoize"); /* assigns and pops memoize */
+		lua_getfield(L, -1, "memoize"); /* gets memoize back. */
+		assert(! lua_isnil(L, -1));
+	}
+	/* Find out whether the fiber is  already in the memoize table. */
+	lua_pushlightuserdata(L, f);
+	lua_gettable(L, -2);
+	if (lua_isnil(L, -1)) { /* no userdata for fiber created so far */
+		lua_pop(L, 1);                  /* pop the nil */
+		lua_pushlightuserdata(L, f);    /* push the key back */
+		/* create a new userdata */
+		void **ptr = lua_newuserdata(L, sizeof(void *));
+		*ptr = f;
+		luaL_getmetatable(L, fiberlib_name);
+		lua_setmetatable(L, -2);
+		lua_settable(L, -3);            /* memoize it */
+		lua_pushlightuserdata(L, f);
+		lua_gettable(L, -2);            /* get it back */
+	}
+	/*
+	 * Here we have a userdata on top of the stack and
+	 * possibly some garbage just under the top. Move the
+	 * result to the beginning of the stack and clear the rest.
+	 */
+	lua_replace(L, top); /* moves the current top to the old top */
+	lua_settop(L, top); /* clears everything after the old top */
+}
+
+static struct fiber *
 lbox_checkfiber(struct lua_State *L, int index)
 {
 	return *(void **) luaL_checkudata(L, index, fiberlib_name);
 }
 
-int
+static int
 lbox_fiber_id(struct lua_State *L)
 {
 	struct fiber *f = lbox_checkfiber(L, 1);
@@ -267,7 +320,7 @@ lbox_fiber_id(struct lua_State *L)
  *
  * Only the current fiber can be made to sleep.
  */
-int
+static int
 lbox_fiber_sleep(struct lua_State *L)
 {
 	if (! lua_isnumber(L, 1) || lua_gettop(L) != 1)
@@ -277,20 +330,17 @@ lbox_fiber_sleep(struct lua_State *L)
 	return 0;
 }
 
-int
+static int
 lbox_fiber_self(struct lua_State *L)
 {
-	void **ptr = lua_newuserdata(L, sizeof(void *));
-	luaL_getmetatable(L, fiberlib_name);
-	lua_setmetatable(L, -2);
-	*ptr = fiber;
+	lbox_pushfiber(L, fiber);
 	return 1;
 }
 
 /** Running and suspended fibers can be cancelled.
  * Zombie fibers can't.
  */
-int
+static int
 lbox_fiber_cancel(struct lua_State *L)
 {
 	struct fiber *f = lbox_checkfiber(L, 1);
@@ -306,7 +356,7 @@ lbox_fiber_cancel(struct lua_State *L)
  * throw an exception if this is the case.
  */
 
-int
+static int
 lbox_fiber_testcancel(struct lua_State *L)
 {
 	if (lua_gettop(L) != 0)
@@ -331,8 +381,9 @@ static const struct luaL_reg fiberlib[] = {
 /* }}} */
 
 /*
- * lua_tostring does no use __tostring metamethod, and it has
- * to be called if we want to print Lua userdata correctly.
+ * This function exists because lua_tostring does not use
+ * __tostring metamethod, and this metamethod has to be used
+ * if we want to print Lua userdata correctly.
  */
 const char *
 tarantool_lua_tostring(struct lua_State *L, int index)
@@ -381,10 +432,10 @@ tarantool_lua_printstack(struct lua_State *L, struct tbuf *out)
  * administrative command.
  *
  * Note: administrative console output must be YAML-compatible.
- * If this is * done automatically, the result is ugly, so we
- * don't do it. A creator of Lua procedures has to do it herself.
- * Best we can do here is to add a trailing \r\n if it's
- * forgotten.
+ * If this is done automatically, the result is ugly, so we
+ * don't do it. Creators of Lua procedures have to do it
+ * themselves. Best we can do here is to add a trailing
+ * \r\n if it's forgotten.
  */
 static int
 lbox_print(struct lua_State *L)
@@ -508,7 +559,8 @@ tarantool_lua(struct lua_State *L,
  * Check if the given literal is a number/boolean or string
  * literal. A string literal needs quotes.
  */
-static bool is_string(const char *str)
+static bool
+is_string(const char *str)
 {
 	if (strcmp(str, "true") == 0 || strcmp(str, "false") == 0)
 	    return false;
@@ -524,7 +576,8 @@ static bool is_string(const char *str)
  * as functional to convert the given configuration to a Lua
  * table and export the table into Lua.
  */
-void tarantool_lua_load_cfg(struct lua_State *L, struct tarantool_cfg *cfg)
+void
+tarantool_lua_load_cfg(struct lua_State *L, struct tarantool_cfg *cfg)
 {
 	luaL_Buffer b;
 	char *key, *value;
diff --git a/test/box/lua.result b/test/box/lua.result
index 0c28179dbdaef6295cd75d07609c381d1c33e71e..5ad20fae0032aeee5d7754e75e357bf5b363ecb6 100644
--- a/test/box/lua.result
+++ b/test/box/lua.result
@@ -553,3 +553,10 @@ lua f:id(), box.fiber.self():id()
  - 110
  - 110
 ...
+lua g = box.fiber.self()
+---
+...
+lua f==g
+---
+ - true
+...
diff --git a/test/box/lua.test b/test/box/lua.test
index e887edfc9dbc8a6dcca15f03eb01f765453d1e81..d9242622cf6ca98d168780aa41fed9663a73fae3 100644
--- a/test/box/lua.test
+++ b/test/box/lua.test
@@ -152,3 +152,5 @@ exec admin "lua box.fiber.cancel(f)"
 exec admin "lua f:id(), box.fiber.self():id()"
 exec admin "lua box.fiber.cancel(box.fiber.self())"
 exec admin "lua f:id(), box.fiber.self():id()"
+exec admin "lua g = box.fiber.self()"
+exec admin "lua f==g"