aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/malloc.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2015-10-04 20:56:11 -0700
committerAustin Clements <austin@google.com>2015-10-09 19:39:03 +0000
commit65aa2da61793846b9929c239dcbdb266490335e5 (patch)
treea0d532c7f8256a304ab3c3189d808e5a0881a2b8 /src/runtime/malloc.go
parent89c341c5e969b571a9475b263b237a8a25efd76b (diff)
downloadgo-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.go35
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