mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: bound defer pools
The unbounded list-based defer pool can grow infinitely. This can happen if a goroutine routinely allocates a defer; then blocks on one P; and then unblocked, scheduled and frees the defer on another P. The scenario was reported on golang-nuts list. We've been here several times. Any unbounded local caches are bad and grow to infinite size. This change introduces central defer pool; local pools become fixed-size with the only purpose of amortizing accesses to the central pool. Change-Id: Iadcfb113ccecf912e1b64afc07926f0de9de2248 Reviewed-on: https://go-review.googlesource.com/3741 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
71be013842
commit
8059071153
4 changed files with 66 additions and 18 deletions
|
|
@ -166,9 +166,20 @@ func newdefer(siz int32) *_defer {
|
|||
mp := acquirem()
|
||||
if sc < uintptr(len(p{}.deferpool)) {
|
||||
pp := mp.p
|
||||
d = pp.deferpool[sc]
|
||||
if d != nil {
|
||||
pp.deferpool[sc] = d.link
|
||||
if len(pp.deferpool[sc]) == 0 {
|
||||
lock(&sched.deferlock)
|
||||
for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
|
||||
d := sched.deferpool[sc]
|
||||
sched.deferpool[sc] = d.link
|
||||
d.link = nil
|
||||
pp.deferpool[sc] = append(pp.deferpool[sc], d)
|
||||
}
|
||||
unlock(&sched.deferlock)
|
||||
}
|
||||
if ln := len(pp.deferpool[sc]); ln > 0 {
|
||||
d = pp.deferpool[sc][ln-1]
|
||||
pp.deferpool[sc][ln-1] = nil
|
||||
pp.deferpool[sc] = pp.deferpool[sc][:ln-1]
|
||||
}
|
||||
}
|
||||
if d == nil {
|
||||
|
|
@ -214,9 +225,28 @@ func freedefer(d *_defer) {
|
|||
if sc < uintptr(len(p{}.deferpool)) {
|
||||
mp := acquirem()
|
||||
pp := mp.p
|
||||
if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
|
||||
// Transfer half of local cache to the central cache.
|
||||
var first, last *_defer
|
||||
for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
|
||||
ln := len(pp.deferpool[sc])
|
||||
d := pp.deferpool[sc][ln-1]
|
||||
pp.deferpool[sc][ln-1] = nil
|
||||
pp.deferpool[sc] = pp.deferpool[sc][:ln-1]
|
||||
if first == nil {
|
||||
first = d
|
||||
} else {
|
||||
last.link = d
|
||||
}
|
||||
last = d
|
||||
}
|
||||
lock(&sched.deferlock)
|
||||
last.link = sched.deferpool[sc]
|
||||
sched.deferpool[sc] = first
|
||||
unlock(&sched.deferlock)
|
||||
}
|
||||
*d = _defer{}
|
||||
d.link = pp.deferpool[sc]
|
||||
pp.deferpool[sc] = d
|
||||
pp.deferpool[sc] = append(pp.deferpool[sc], d)
|
||||
releasem(mp)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue