diff --git a/src/runtime/gc_leaking.go b/src/runtime/gc_leaking.go index 71c4258b67..d878ce40a6 100644 --- a/src/runtime/gc_leaking.go +++ b/src/runtime/gc_leaking.go @@ -7,6 +7,7 @@ package runtime // may be the only memory allocator possible. import ( + "internal/task" "unsafe" ) @@ -19,6 +20,9 @@ var gcTotalAlloc uint64 // Total number of calls to alloc() var gcMallocs uint64 +// Heap lock for parallel goroutines. No-op when single threaded. +var gcLock task.PMutex + // Total number of objected freed; for leaking collector this stays 0 const gcFrees = 0 @@ -30,6 +34,7 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { // TODO: this can be optimized by not casting between pointers and ints so // much. And by using platform-native data types (e.g. *uint8 for 8-bit // systems). + gcLock.Lock() size = align(size) addr := heapptr gcTotalAlloc += uint64(size) @@ -43,6 +48,8 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { // Failed to make the heap bigger, so we must really be out of memory. runtimePanic("out of memory") } + gcLock.Unlock() + pointer := unsafe.Pointer(addr) zero_new_alloc(pointer, size) return pointer @@ -69,6 +76,8 @@ func free(ptr unsafe.Pointer) { // The returned memory statistics are up to date as of the // call to ReadMemStats. This would not do GC implicitly for you. func ReadMemStats(m *MemStats) { + gcLock.Lock() + m.HeapIdle = 0 m.HeapInuse = gcTotalAlloc m.HeapReleased = 0 // always 0, we don't currently release memory back to the OS. @@ -82,6 +91,8 @@ func ReadMemStats(m *MemStats) { // no free -- current in use heap is the total allocated m.HeapAlloc = gcTotalAlloc m.Alloc = m.HeapAlloc + + gcLock.Unlock() } func GC() {