Skip to content

Commit 1be9858

Browse files
committed
runtime: prepare the leaking GC for concurrent operations
This uses the internal/llsync package to convert some non-atomic operations to pseudo-atomic operations that will become truly atomic on systems that need this (such as multicore chips and when we implement true parallelism on Linux).
1 parent 83dac2f commit 1be9858

File tree

1 file changed

+20
-13
lines changed

1 file changed

+20
-13
lines changed

src/runtime/gc_leaking.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ package runtime
77
// may be the only memory allocator possible.
88

99
import (
10+
"internal/task"
1011
"unsafe"
1112
)
1213

1314
// Ever-incrementing pointer: no memory is freed.
14-
var heapptr = heapStart
15+
var heapptr task.Uintptr
1516

1617
// Total amount allocated for runtime.MemStats
17-
var gcTotalAlloc uint64
18+
var gcTotalAlloc task.Uint64
1819

1920
// Total number of calls to alloc()
20-
var gcMallocs uint64
21+
var gcMallocs task.Uint64
2122

2223
// Total number of objected freed; for leaking collector this stays 0
2324
const gcFrees = 0
@@ -31,18 +32,23 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
3132
// much. And by using platform-native data types (e.g. *uint8 for 8-bit
3233
// systems).
3334
size = align(size)
34-
addr := heapptr
35-
gcTotalAlloc += uint64(size)
36-
gcMallocs++
37-
heapptr += size
38-
for heapptr >= heapEnd {
35+
36+
// Track statistics. These are stored separately so are not strictly atomic,
37+
// which means that ReadMemStats might read a _slightly_ inconsistent state.
38+
gcTotalAlloc.Add(uint64(size))
39+
gcMallocs.Add(1)
40+
41+
nextAddr := heapptr.Add(size)
42+
for nextAddr >= heapEnd {
3943
// Try to increase the heap and check again.
4044
if growHeap() {
4145
continue
4246
}
4347
// Failed to make the heap bigger, so we must really be out of memory.
4448
runtimePanic("out of memory")
4549
}
50+
addr := nextAddr - size
51+
4652
pointer := unsafe.Pointer(addr)
4753
zero_new_alloc(pointer, size)
4854
return pointer
@@ -69,18 +75,19 @@ func free(ptr unsafe.Pointer) {
6975
// The returned memory statistics are up to date as of the
7076
// call to ReadMemStats. This would not do GC implicitly for you.
7177
func ReadMemStats(m *MemStats) {
78+
totalAlloc := gcTotalAlloc.Load()
7279
m.HeapIdle = 0
73-
m.HeapInuse = gcTotalAlloc
80+
m.HeapInuse = totalAlloc
7481
m.HeapReleased = 0 // always 0, we don't currently release memory back to the OS.
7582

7683
m.HeapSys = m.HeapInuse + m.HeapIdle
7784
m.GCSys = 0
78-
m.TotalAlloc = gcTotalAlloc
79-
m.Mallocs = gcMallocs
85+
m.TotalAlloc = totalAlloc
86+
m.Mallocs = gcMallocs.Load()
8087
m.Frees = gcFrees
8188
m.Sys = uint64(heapEnd - heapStart)
8289
// no free -- current in use heap is the total allocated
83-
m.HeapAlloc = gcTotalAlloc
90+
m.HeapAlloc = totalAlloc
8491
m.Alloc = m.HeapAlloc
8592
}
8693

@@ -94,7 +101,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
94101

95102
func initHeap() {
96103
// preinit() may have moved heapStart; reset heapptr
97-
heapptr = heapStart
104+
heapptr.Store(heapStart)
98105
}
99106

100107
// setHeapEnd sets a new (larger) heapEnd pointer.

0 commit comments

Comments
 (0)