diff --git a/app/dispatcher/default.go b/app/dispatcher/default.go
index 5a55c1b2..dceba917 100644
--- a/app/dispatcher/default.go
+++ b/app/dispatcher/default.go
@@ -37,7 +37,7 @@ func (r *cachedReader) Cache(b *buf.Buffer) {
 	mb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
 	r.Lock()
 	if !mb.IsEmpty() {
-		common.Must(r.cache.WriteMultiBuffer(mb))
+		r.cache, _ = buf.MergeMulti(r.cache, mb)
 	}
 	b.Clear()
 	rawBytes := b.Extend(buf.Size)
@@ -75,8 +75,7 @@ func (r *cachedReader) ReadMultiBufferTimeout(timeout time.Duration) (buf.MultiB
 func (r *cachedReader) CloseError() {
 	r.Lock()
 	if r.cache != nil {
-		r.cache.Release()
-		r.cache = nil
+		r.cache = buf.ReleaseMulti(r.cache)
 	}
 	r.Unlock()
 	r.reader.CloseError()
diff --git a/app/dispatcher/stats_test.go b/app/dispatcher/stats_test.go
index 5a42faa3..7091e7e6 100644
--- a/app/dispatcher/stats_test.go
+++ b/app/dispatcher/stats_test.go
@@ -36,7 +36,7 @@ func TestStatsWriter(t *testing.T) {
 	common.Must2(mb.Write([]byte("abcd")))
 	common.Must(writer.WriteMultiBuffer(mb))
 
-	mb.Release()
+	mb = buf.ReleaseMulti(mb)
 	common.Must2(mb.Write([]byte("efg")))
 	common.Must(writer.WriteMultiBuffer(mb))
 
diff --git a/common/buf/multi_buffer.go b/common/buf/multi_buffer.go
index e03d950b..ce1a21cc 100644
--- a/common/buf/multi_buffer.go
+++ b/common/buf/multi_buffer.go
@@ -13,7 +13,7 @@ func ReadAllToMultiBuffer(reader io.Reader) (MultiBuffer, error) {
 	mb := make(MultiBuffer, 0, 128)
 
 	if _, err := mb.ReadFrom(reader); err != nil {
-		mb.Release()
+		ReleaseMulti(mb)
 		return nil, err
 	}
 
@@ -31,7 +31,7 @@ func ReadAllToBytes(reader io.Reader) ([]byte, error) {
 	}
 	b := make([]byte, mb.Len())
 	common.Must2(mb.Read(b))
-	mb.Release()
+	ReleaseMulti(mb)
 	return b, nil
 }
 
@@ -47,6 +47,15 @@ func MergeMulti(dest MultiBuffer, src MultiBuffer) (MultiBuffer, MultiBuffer) {
 	return dest, src[:0]
 }
 
+// ReleaseMulti release all content of the MultiBuffer, and returns an empty MultiBuffer.
+func ReleaseMulti(mb MultiBuffer) MultiBuffer {
+	for i := range mb {
+		mb[i].Release()
+		mb[i] = nil
+	}
+	return mb[:0]
+}
+
 // Copy copied the beginning part of the MultiBuffer into the given byte array.
 func (mb MultiBuffer) Copy(b []byte) int {
 	total := 0
@@ -107,7 +116,9 @@ func (mb *MultiBuffer) Read(b []byte) (int, error) {
 
 // WriteTo implements io.WriterTo.
 func (mb *MultiBuffer) WriteTo(writer io.Writer) (int64, error) {
-	defer mb.Release()
+	defer func() {
+		*mb = ReleaseMulti(*mb)
+	}()
 
 	totalBytes := int64(0)
 	for _, b := range *mb {
@@ -143,10 +154,7 @@ func (mb *MultiBuffer) Write(b []byte) (int, error) {
 
 // WriteMultiBuffer implements Writer.
 func (mb *MultiBuffer) WriteMultiBuffer(b MultiBuffer) error {
-	*mb = append(*mb, b...)
-	for i := range b {
-		b[i] = nil
-	}
+	*mb, _ = MergeMulti(*mb, b)
 	return nil
 }
 
@@ -173,15 +181,7 @@ func (mb MultiBuffer) IsEmpty() bool {
 	return true
 }
 
-// Release releases all Buffers in the MultiBuffer.
-func (mb *MultiBuffer) Release() {
-	for i, b := range *mb {
-		b.Release()
-		(*mb)[i] = nil
-	}
-	*mb = nil
-}
-
+// String returns the content of the MultiBuffer in string.
 func (mb MultiBuffer) String() string {
 	v := make([]interface{}, len(mb))
 	for i, b := range mb {
diff --git a/common/buf/reader.go b/common/buf/reader.go
index fb1dd488..90baa48c 100644
--- a/common/buf/reader.go
+++ b/common/buf/reader.go
@@ -49,7 +49,6 @@ func (r *BufferedReader) Read(b []byte) (int, error) {
 		nBytes, err := r.Buffer.Read(b)
 		common.Must(err)
 		if r.Buffer.IsEmpty() {
-			r.Buffer.Release()
 			r.Buffer = nil
 		}
 		return nBytes, nil
@@ -123,7 +122,8 @@ func (r *BufferedReader) WriteTo(writer io.Writer) (int64, error) {
 // Close implements io.Closer.
 func (r *BufferedReader) Close() error {
 	if !r.Buffer.IsEmpty() {
-		r.Buffer.Release()
+		ReleaseMulti(r.Buffer)
+		r.Buffer = nil
 	}
 	return common.Close(r.Reader)
 }
diff --git a/common/buf/readv_reader.go b/common/buf/readv_reader.go
index f127ccde..ef10ead3 100644
--- a/common/buf/readv_reader.go
+++ b/common/buf/readv_reader.go
@@ -83,14 +83,12 @@ func (r *ReadVReader) readMulti() (MultiBuffer, error) {
 	r.mr.Clear()
 
 	if err != nil {
-		mb := MultiBuffer(bs)
-		mb.Release()
+		ReleaseMulti(MultiBuffer(bs))
 		return nil, err
 	}
 
 	if nBytes == 0 {
-		mb := MultiBuffer(bs)
-		mb.Release()
+		ReleaseMulti(MultiBuffer(bs))
 		return nil, io.EOF
 	}
 
diff --git a/common/buf/writer.go b/common/buf/writer.go
index 7caabd09..b6d5a15b 100644
--- a/common/buf/writer.go
+++ b/common/buf/writer.go
@@ -18,7 +18,7 @@ type BufferToBytesWriter struct {
 
 // WriteMultiBuffer implements Writer. This method takes ownership of the given buffer.
 func (w *BufferToBytesWriter) WriteMultiBuffer(mb MultiBuffer) error {
-	defer mb.Release()
+	defer ReleaseMulti(mb)
 
 	size := mb.Len()
 	if size == 0 {
@@ -134,7 +134,7 @@ func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
 		return w.writer.WriteMultiBuffer(b)
 	}
 
-	defer b.Release()
+	defer ReleaseMulti(b)
 
 	for !b.IsEmpty() {
 		if w.buffer == nil {
@@ -216,7 +216,7 @@ type SequentialWriter struct {
 
 // WriteMultiBuffer implements Writer.
 func (w *SequentialWriter) WriteMultiBuffer(mb MultiBuffer) error {
-	defer mb.Release()
+	defer ReleaseMulti(mb)
 
 	for _, b := range mb {
 		if b.IsEmpty() {
@@ -234,7 +234,7 @@ func (w *SequentialWriter) WriteMultiBuffer(mb MultiBuffer) error {
 type noOpWriter byte
 
 func (noOpWriter) WriteMultiBuffer(b MultiBuffer) error {
-	b.Release()
+	ReleaseMulti(b)
 	return nil
 }
 
diff --git a/common/crypto/auth.go b/common/crypto/auth.go
index a1202b40..35147200 100644
--- a/common/crypto/auth.go
+++ b/common/crypto/auth.go
@@ -202,7 +202,7 @@ func (r *AuthenticationReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
 	const readSize = 16
 	mb := make(buf.MultiBuffer, 0, readSize)
 	if err := r.readInternal(false, &mb); err != nil {
-		mb.Release()
+		buf.ReleaseMulti(mb)
 		return nil, err
 	}
 
@@ -212,7 +212,7 @@ func (r *AuthenticationReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
 			break
 		}
 		if err != nil {
-			mb.Release()
+			buf.ReleaseMulti(mb)
 			return nil, err
 		}
 	}
@@ -269,7 +269,7 @@ func (w *AuthenticationWriter) seal(b []byte) (*buf.Buffer, error) {
 }
 
 func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
-	defer mb.Release()
+	defer buf.ReleaseMulti(mb)
 
 	var maxPadding int32
 	if w.padding != nil {
@@ -286,7 +286,7 @@ func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
 		b.Release()
 
 		if err != nil {
-			mb2Write.Release()
+			buf.ReleaseMulti(mb2Write)
 			return err
 		}
 		mb2Write = append(mb2Write, eb)
@@ -299,7 +299,7 @@ func (w *AuthenticationWriter) writeStream(mb buf.MultiBuffer) error {
 }
 
 func (w *AuthenticationWriter) writePacket(mb buf.MultiBuffer) error {
-	defer mb.Release()
+	defer buf.ReleaseMulti(mb)
 
 	mb2Write := make(buf.MultiBuffer, 0, len(mb)+1)
 
diff --git a/common/mux/writer.go b/common/mux/writer.go
index cd6daf1f..2dc3904c 100644
--- a/common/mux/writer.go
+++ b/common/mux/writer.go
@@ -85,7 +85,7 @@ func (w *Writer) writeData(mb buf.MultiBuffer) error {
 
 // WriteMultiBuffer implements buf.Writer.
 func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
-	defer mb.Release()
+	defer buf.ReleaseMulti(mb)
 
 	if mb.IsEmpty() {
 		return w.writeMetaOnly()
diff --git a/common/platform/ctlcmd/ctlcmd.go b/common/platform/ctlcmd/ctlcmd.go
index 0e1506c3..45932953 100644
--- a/common/platform/ctlcmd/ctlcmd.go
+++ b/common/platform/ctlcmd/ctlcmd.go
@@ -37,8 +37,8 @@ func Run(args []string, input io.Reader) (buf.MultiBuffer, error) {
 		if errBuffer.Len() > 0 {
 			msg += ": " + errBuffer.String()
 		}
-		errBuffer.Release()
-		outBuffer.Release()
+		buf.ReleaseMulti(errBuffer)
+		buf.ReleaseMulti(outBuffer)
 		return nil, newError(msg).Base(err)
 	}
 
diff --git a/functions.go b/functions.go
index 5fb39dc2..6c49a2d8 100644
--- a/functions.go
+++ b/functions.go
@@ -1,10 +1,10 @@
 package core
 
 import (
+	"bytes"
 	"context"
 
 	"v2ray.com/core/common"
-	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/features/routing"
 )
@@ -21,11 +21,7 @@ func CreateObject(v *Instance, config interface{}) (interface{}, error) {
 // StartInstance starts a new V2Ray instance with given serialized config.
 // By default V2Ray only support config in protobuf format, i.e., configFormat = "protobuf". Caller need to load other packages to add JSON support.
 func StartInstance(configFormat string, configBytes []byte) (*Instance, error) {
-	var mb buf.MultiBuffer
-	defer mb.Release()
-
-	common.Must2(mb.Write(configBytes))
-	config, err := LoadConfig(configFormat, "", &mb)
+	config, err := LoadConfig(configFormat, "", bytes.NewReader(configBytes))
 	if err != nil {
 		return nil, err
 	}
diff --git a/main/confloader/external/external.go b/main/confloader/external/external.go
index 4c78ef6e..ef5611fe 100644
--- a/main/confloader/external/external.go
+++ b/main/confloader/external/external.go
@@ -17,7 +17,8 @@ type ClosableMultiBuffer struct {
 }
 
 func (c *ClosableMultiBuffer) Close() error {
-	c.MultiBuffer.Release()
+	buf.ReleaseMulti(c.MultiBuffer)
+	c.MultiBuffer = nil
 	return nil
 }
 
diff --git a/proxy/shadowsocks/ota.go b/proxy/shadowsocks/ota.go
index 7a5cf1b4..ab0d3b59 100644
--- a/proxy/shadowsocks/ota.go
+++ b/proxy/shadowsocks/ota.go
@@ -114,7 +114,7 @@ func NewChunkWriter(writer io.Writer, auth *Authenticator) *ChunkWriter {
 
 // WriteMultiBuffer implements buf.Writer.
 func (w *ChunkWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
-	defer mb.Release()
+	defer buf.ReleaseMulti(mb)
 
 	for {
 		payloadLen, _ := mb.Read(w.buffer[2+AuthSize:])
diff --git a/transport/internet/kcp/connection.go b/transport/internet/kcp/connection.go
index 7fd67d03..31494006 100644
--- a/transport/internet/kcp/connection.go
+++ b/transport/internet/kcp/connection.go
@@ -377,7 +377,7 @@ func (c *Connection) Write(b []byte) (int, error) {
 
 // WriteMultiBuffer implements buf.Writer.
 func (c *Connection) WriteMultiBuffer(mb buf.MultiBuffer) error {
-	defer mb.Release()
+	defer buf.ReleaseMulti(mb)
 
 	updatePending := false
 	defer func() {
diff --git a/transport/internet/kcp/receiving.go b/transport/internet/kcp/receiving.go
index 68815140..86c389e1 100644
--- a/transport/internet/kcp/receiving.go
+++ b/transport/internet/kcp/receiving.go
@@ -151,7 +151,8 @@ func NewReceivingWorker(kcp *Connection) *ReceivingWorker {
 
 func (w *ReceivingWorker) Release() {
 	w.Lock()
-	w.leftOver.Release()
+	buf.ReleaseMulti(w.leftOver)
+	w.leftOver = nil
 	w.Unlock()
 }
 
diff --git a/transport/pipe/impl.go b/transport/pipe/impl.go
index a2df2787..d5e929c9 100644
--- a/transport/pipe/impl.go
+++ b/transport/pipe/impl.go
@@ -144,10 +144,10 @@ func (p *pipe) WriteMultiBuffer(mb buf.MultiBuffer) error {
 			runtime.Gosched()
 			return nil
 		case err == errBufferFull && p.option.discardOverflow:
-			mb.Release()
+			buf.ReleaseMulti(mb)
 			return nil
 		case err != errBufferFull:
-			mb.Release()
+			buf.ReleaseMulti(mb)
 			p.readSignal.Signal()
 			return err
 		}
@@ -184,7 +184,7 @@ func (p *pipe) CloseError() {
 	p.state = errord
 
 	if !p.data.IsEmpty() {
-		p.data.Release()
+		buf.ReleaseMulti(p.data)
 		p.data = nil
 	}