aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
authorcch123 <buaa.cch@gmail.com>2020-10-19 12:55:46 +0000
committerFilippo Valsorda <filippo@golang.org>2020-11-09 13:12:41 +0000
commit22312437ee1e72451c70b79c90e36ad0b849e3f6 (patch)
treea644b28e7780c599285c8dc65b9b7814228bb6b6 /src/crypto
parent7307e86afda3c5c7f6158d2469c39606fd1dba65 (diff)
downloadgo-22312437ee1e72451c70b79c90e36ad0b849e3f6.tar.gz
go-22312437ee1e72451c70b79c90e36ad0b849e3f6.zip
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 <filippo@golang.org> Change-Id: I5f28673f95d4568b7d13dbc20e9d4b48d481a93d Reviewed-on: https://go-review.googlesource.com/c/go/+/267957 Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Filippo Valsorda <filippo@golang.org> Trust: Roland Shoemaker <roland@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org> Reviewed-by: Roberto Clapis <roberto@golang.org>
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/tls/conn.go36
1 files changed, 27 insertions, 9 deletions
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index ada19d6e7a..b9a1095862 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -94,7 +94,6 @@ type Conn struct {
rawInput bytes.Buffer // raw input, starting with a record header
input bytes.Reader // application data waiting to be read, from rawInput.Next
hand bytes.Buffer // handshake data waiting to be read
- outBuf []byte // scratch buffer used by out.encrypt
buffering bool // whether records are buffered in sendBuf
sendBuf []byte // a buffer of records waiting to be sent
@@ -928,9 +927,28 @@ func (c *Conn) flush() (int, error) {
return n, err
}
+// outBufPool pools the record-sized scratch buffers used by writeRecordLocked.
+var outBufPool = sync.Pool{
+ New: func() interface{} {
+ return new([]byte)
+ },
+}
+
// writeRecordLocked writes a TLS record with the given type and payload to the
// connection and updates the record layer state.
func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
+ outBufPtr := outBufPool.Get().(*[]byte)
+ outBuf := *outBufPtr
+ defer func() {
+ // You might be tempted to simplify this by just passing &outBuf to Put,
+ // but that would make the local copy of the outBuf slice header escape
+ // to the heap, causing an allocation. Instead, we keep around the
+ // pointer to the slice header returned by Get, which is already on the
+ // heap, and overwrite and return that.
+ *outBufPtr = outBuf
+ outBufPool.Put(outBufPtr)
+ }()
+
var n int
for len(data) > 0 {
m := len(data)
@@ -938,8 +956,8 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
m = maxPayload
}
- _, c.outBuf = sliceForAppend(c.outBuf[:0], recordHeaderLen)
- c.outBuf[0] = byte(typ)
+ _, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen)
+ outBuf[0] = byte(typ)
vers := c.vers
if vers == 0 {
// Some TLS servers fail if the record version is
@@ -950,17 +968,17 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
// See RFC 8446, Section 5.1.
vers = VersionTLS12
}
- c.outBuf[1] = byte(vers >> 8)
- c.outBuf[2] = byte(vers)
- c.outBuf[3] = byte(m >> 8)
- c.outBuf[4] = byte(m)
+ outBuf[1] = byte(vers >> 8)
+ outBuf[2] = byte(vers)
+ outBuf[3] = byte(m >> 8)
+ outBuf[4] = byte(m)
var err error
- c.outBuf, err = c.out.encrypt(c.outBuf, data[:m], c.config.rand())
+ outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand())
if err != nil {
return n, err
}
- if _, err := c.write(c.outBuf); err != nil {
+ if _, err := c.write(outBuf); err != nil {
return n, err
}
n += m