diff options
| author | Austin Clements <austin@google.com> | 2015-10-04 20:56:11 -0700 |
|---|---|---|
| committer | Austin Clements <austin@google.com> | 2015-10-09 19:39:03 +0000 |
| commit | 65aa2da61793846b9929c239dcbdb266490335e5 (patch) | |
| tree | a0d532c7f8256a304ab3c3189d808e5a0881a2b8 /src/runtime/malloc.go | |
| parent | 89c341c5e969b571a9475b263b237a8a25efd76b (diff) | |
| download | go-65aa2da61793846b9929c239dcbdb266490335e5.tar.xz | |
runtime: assist before allocating
Currently, when the mutator allocates, the runtime first allocates the
memory and then, if that G has done "enough" allocation, the runtime
checks whether the G has assist debt to pay off and, if so, pays it
off. This approach leads to under-assisting, where a G can allocate a
large region (or many small regions) before paying for it, or can even
exit with outstanding debt.
This commit flips this around so that a G always acquires enough
credit for an allocation before it can perform that allocation. We
continue to amortize the cost of assists by requiring that they
over-assist when triggered to build up credit for many allocations.
Fixes #11967.
Change-Id: Idac9f11133b328535667674d837be72c23ebd899
Reviewed-on: https://go-review.googlesource.com/15409
Reviewed-by: Rick Hudson <rlh@golang.org>
Run-TryBot: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/malloc.go')
| -rw-r--r-- | src/runtime/malloc.go | 35 |
1 files changed, 28 insertions, 7 deletions
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 29f81a09f5..6c7db0ffff 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -510,6 +510,27 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { return persistentalloc(size, align, &memstats.other_sys) } + // assistG is the G to charge for this allocation, or nil if + // GC is not currently active. + var assistG *g + if gcBlackenEnabled != 0 { + // Charge the current user G for this allocation. + assistG = getg() + if assistG.m.curg != nil { + assistG = assistG.m.curg + } + // Charge the allocation against the G. We'll account + // for internal fragmentation at the end of mallocgc. + assistG.gcAssistBytes -= int64(size) + + if assistG.gcAssistBytes < 0 { + // This G is in debt. Assist the GC to correct + // this before allocating. This must happen + // before disabling preemption. + gcAssistAlloc(assistG) + } + } + // Set mp.mallocing to keep from being preempted by GC. mp := acquirem() if mp.mallocing != 0 { @@ -704,15 +725,15 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { } } + if assistG != nil { + // Account for internal fragmentation in the assist + // debt now that we know it. + assistG.gcAssistBytes -= int64(size - dataSize) + } + if shouldhelpgc && shouldtriggergc() { startGC(gcBackgroundMode, false) - } else if gcBlackenEnabled != 0 { - // Assist garbage collector. We delay this until the - // epilogue so that it doesn't interfere with the - // inner working of malloc such as mcache refills that - // might happen while doing the gcAssistAlloc. - gcAssistAlloc(size, shouldhelpgc) - } else if shouldhelpgc && bggc.working != 0 { + } else if shouldhelpgc && bggc.working != 0 && gcBlackenEnabled == 0 { // The GC is starting up or shutting down, so we can't // assist, but we also can't allocate unabated. Slow // down this G's allocation and help the GC stay |
