Skip to content

Commit

Permalink
fix: reduce memory held by deferred objects (#96)
Browse files Browse the repository at this point in the history
`bytes.Buffer` will always overallocate (for performance) and we don't
have a great way of predicting the correct size. So, instead, copy once
when we're done.
  • Loading branch information
Stebalien authored Apr 20, 2024
1 parent c5f90eb commit bb55032
Showing 1 changed file with 17 additions and 5 deletions.
22 changes: 17 additions & 5 deletions deferred.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ import (
"errors"
"fmt"
"io"
"sync"
)

var deferredBufferPool = sync.Pool{
New: func() any {
return bytes.NewBuffer(nil)
},
}

type Deferred struct {
Raw []byte
}
Expand All @@ -24,10 +31,12 @@ func (d *Deferred) MarshalCBOR(w io.Writer) error {
}

func (d *Deferred) UnmarshalCBOR(br io.Reader) (err error) {
// Reuse any existing buffers.
reusedBuf := d.Raw[:0]
d.Raw = nil
buf := bytes.NewBuffer(reusedBuf)
buf := deferredBufferPool.Get().(*bytes.Buffer)

defer func() {
buf.Reset()
deferredBufferPool.Put(buf)
}()

// Allocate some scratch space.
scratch := make([]byte, maxHeaderSize)
Expand Down Expand Up @@ -90,6 +99,9 @@ func (d *Deferred) UnmarshalCBOR(br io.Reader) (err error) {
return fmt.Errorf("unhandled deferred cbor type: %d", maj)
}
}
d.Raw = buf.Bytes()
// Reuse existing buffer. Also, copy to "give back" the allocation in the byte buffer (which
// is likely significant).
d.Raw = d.Raw[:0]
d.Raw = append(d.Raw, buf.Bytes()...)
return nil
}

0 comments on commit bb55032

Please sign in to comment.