Skip to content

Commit 2231243

Browse files
cch123FiloSottile
andcommitted
crypto/tls: pool Conn's outBuf to reduce memory cost of idle connections
Derived from CL 263277, which includes benchmarks. Fixes #42035 Co-authored-by: Filippo Valsorda <[email protected]> Change-Id: I5f28673f95d4568b7d13dbc20e9d4b48d481a93d Reviewed-on: https://go-review.googlesource.com/c/go/+/267957 Run-TryBot: Dmitri Shuralyov <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Filippo Valsorda <[email protected]> Trust: Roland Shoemaker <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-by: Roberto Clapis <[email protected]>
1 parent 7307e86 commit 2231243

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

src/crypto/tls/conn.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ type Conn struct {
9494
rawInput bytes.Buffer // raw input, starting with a record header
9595
input bytes.Reader // application data waiting to be read, from rawInput.Next
9696
hand bytes.Buffer // handshake data waiting to be read
97-
outBuf []byte // scratch buffer used by out.encrypt
9897
buffering bool // whether records are buffered in sendBuf
9998
sendBuf []byte // a buffer of records waiting to be sent
10099

@@ -928,18 +927,37 @@ func (c *Conn) flush() (int, error) {
928927
return n, err
929928
}
930929

930+
// outBufPool pools the record-sized scratch buffers used by writeRecordLocked.
931+
var outBufPool = sync.Pool{
932+
New: func() interface{} {
933+
return new([]byte)
934+
},
935+
}
936+
931937
// writeRecordLocked writes a TLS record with the given type and payload to the
932938
// connection and updates the record layer state.
933939
func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
940+
outBufPtr := outBufPool.Get().(*[]byte)
941+
outBuf := *outBufPtr
942+
defer func() {
943+
// You might be tempted to simplify this by just passing &outBuf to Put,
944+
// but that would make the local copy of the outBuf slice header escape
945+
// to the heap, causing an allocation. Instead, we keep around the
946+
// pointer to the slice header returned by Get, which is already on the
947+
// heap, and overwrite and return that.
948+
*outBufPtr = outBuf
949+
outBufPool.Put(outBufPtr)
950+
}()
951+
934952
var n int
935953
for len(data) > 0 {
936954
m := len(data)
937955
if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload {
938956
m = maxPayload
939957
}
940958

941-
_, c.outBuf = sliceForAppend(c.outBuf[:0], recordHeaderLen)
942-
c.outBuf[0] = byte(typ)
959+
_, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen)
960+
outBuf[0] = byte(typ)
943961
vers := c.vers
944962
if vers == 0 {
945963
// Some TLS servers fail if the record version is
@@ -950,17 +968,17 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
950968
// See RFC 8446, Section 5.1.
951969
vers = VersionTLS12
952970
}
953-
c.outBuf[1] = byte(vers >> 8)
954-
c.outBuf[2] = byte(vers)
955-
c.outBuf[3] = byte(m >> 8)
956-
c.outBuf[4] = byte(m)
971+
outBuf[1] = byte(vers >> 8)
972+
outBuf[2] = byte(vers)
973+
outBuf[3] = byte(m >> 8)
974+
outBuf[4] = byte(m)
957975

958976
var err error
959-
c.outBuf, err = c.out.encrypt(c.outBuf, data[:m], c.config.rand())
977+
outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand())
960978
if err != nil {
961979
return n, err
962980
}
963-
if _, err := c.write(c.outBuf); err != nil {
981+
if _, err := c.write(outBuf); err != nil {
964982
return n, err
965983
}
966984
n += m

0 commit comments

Comments
 (0)