From 959442dc82e082a9c52ebaa831f2a8dab4e793b9 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 5 May 2021 14:52:15 +0200 Subject: [PATCH] unix: use conservative GC by default This commit does two things: 1. It makes it possible to grow the heap on Linux and MacOS by allocating 1GB of virtual memory on startup and then slowly using it as necessary, when running out of available heap space. 2. It switches the default GC to be the conservative GC (previously extalloc). This is good for consistency with other platforms that all use this same GC. This makes the extalloc GC unused by default. --- compileopts/config.go | 7 +------ src/runtime/os_darwin.go | 8 ++++++++ src/runtime/os_linux.go | 8 ++++++++ src/runtime/runtime_unix.go | 3 +++ src/runtime/runtime_unix_heap.go | 25 +++++++++++++++++++------ 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/compileopts/config.go b/compileopts/config.go index d6979213..6e52c4ff 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -80,12 +80,7 @@ func (c *Config) GC() string { if c.Target.GC != "" { return c.Target.GC } - for _, tag := range c.Target.BuildTags { - if tag == "baremetal" || tag == "wasm" { - return "conservative" - } - } - return "extalloc" + return "conservative" } // NeedsStackObjects returns true if the compiler should insert stack objects diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 60110161..ac31b67d 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -3,3 +3,11 @@ package runtime const GOOS = "darwin" + +const ( + // See https://github.com/golang/go/blob/master/src/syscall/zerrors_darwin_amd64.go + flag_PROT_READ = 0x1 + flag_PROT_WRITE = 0x2 + flag_MAP_PRIVATE = 0x2 + flag_MAP_ANONYMOUS = 0x1000 // MAP_ANON +) diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index ab43c3a4..7613134e 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -3,3 +3,11 @@ package runtime const GOOS = "linux" + +const ( + // See https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/mman-common.h + flag_PROT_READ = 0x1 + flag_PROT_WRITE = 0x2 + flag_MAP_PRIVATE = 0x2 + flag_MAP_ANONYMOUS = 0x20 +) diff --git a/src/runtime/runtime_unix.go b/src/runtime/runtime_unix.go index 59a28682..584f0338 100644 --- a/src/runtime/runtime_unix.go +++ b/src/runtime/runtime_unix.go @@ -16,6 +16,9 @@ func usleep(usec uint) int //export malloc func malloc(size uintptr) unsafe.Pointer +//export mmap +func mmap(addr unsafe.Pointer, length, prot, flags, fd int, offset int) unsafe.Pointer + //export abort func abort() diff --git a/src/runtime/runtime_unix_heap.go b/src/runtime/runtime_unix_heap.go index 98ad8075..cee1f1e1 100644 --- a/src/runtime/runtime_unix_heap.go +++ b/src/runtime/runtime_unix_heap.go @@ -5,20 +5,33 @@ package runtime -const heapSize = 1 * 1024 * 1024 // 1MB to start +var heapSize uintptr = 128 * 1024 // small amount to start +const heapMaxSize = 1 * 1024 * 1024 * 1024 // 1GB for the entire heap var heapStart, heapEnd uintptr func preinit() { - heapStart = uintptr(malloc(heapSize)) + // Allocate a large chunk of virtual memory. Because it is virtual, it won't + // really be allocated in RAM. Memory will only be allocated when it is + // first touched. + addr := mmap(nil, heapMaxSize, flag_PROT_READ|flag_PROT_WRITE, flag_MAP_PRIVATE|flag_MAP_ANONYMOUS, -1, 0) + heapStart = uintptr(addr) heapEnd = heapStart + heapSize } // growHeap tries to grow the heap size. It returns true if it succeeds, false // otherwise. func growHeap() bool { - // At the moment, this is not possible. However it shouldn't be too - // difficult (at least on Linux) to allocate a large amount of virtual - // memory at startup that is then slowly used. - return false + if heapSize == heapMaxSize { + // Already at the max. If we run out of memory, we should consider + // increasing heapMaxSize on 64-bit systems. + return false + } + // Grow the heap size used by the program. + heapSize = (heapSize * 4 / 3) &^ 4095 // grow by around 33% + if heapSize > heapMaxSize { + heapSize = heapMaxSize + } + setHeapEnd(heapStart + heapSize) + return true }