diff --git a/doc/godebug.md b/doc/godebug.md index 50033b6f1770b8..f7baea30b2d516 100644 --- a/doc/godebug.md +++ b/doc/godebug.md @@ -165,6 +165,19 @@ when the connection supports neither TLS 1.3 nor Extended Master Secret (implemented in Go 1.21). It can be reenabled with the [`tlsunsafeekm` setting](/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial). +Go 1.22 changed how the runtime interacts with transparent huge pages on Linux. +In particular, a common default Linux kernel configuration can result in +significant memory overheads, and Go 1.22 no longer works around this default. +To work around this issue without adjusting kernel settings, transparent huge +pages can be disabled for Go memory with the +[`disablethp` setting](/pkg/runtime#hdr-Environment_Variable). +This behavior was backported to Go 1.21.1, but the setting is only available +starting with Go 1.21.6. +This setting may be removed in a future release, and users impacted by this issue +should adjust their Linux configuration according to the recommendations in the +[GC guide](/doc/gc-guide#Linux_transparent_huge_pages), or switch to a Linux +distribution that disables transparent huge pages altogether. + ### Go 1.21 Go 1.21 made it a run-time error to call `panic` with a nil interface value, diff --git a/src/runtime/extern.go b/src/runtime/extern.go index d199720b9b05cf..03050df7661d38 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -55,6 +55,13 @@ It is a comma-separated list of name=val pairs setting these named variables: cgocheck mode can be enabled using GOEXPERIMENT (which requires a rebuild), see https://pkg.go.dev/internal/goexperiment for details. + disablethp: setting disablethp=1 on Linux disables transparent huge pages for the heap. + It has no effect on other platforms. disablethp is meant for compatibility with versions + of Go before 1.21, which stopped working around a Linux kernel default that can result + in significant memory overuse. See https://go.dev/issue/64332. This setting will be + removed in a future release, so operators should tweak their Linux configuration to suit + their needs before then. See https://go.dev/doc/gc-guide#Linux_transparent_huge_pages. + dontfreezetheworld: by default, the start of a fatal panic or throw "freezes the world", preempting all threads to stop all running goroutines, which makes it possible to traceback all goroutines, and diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go index c9823d30113310..d63c38c209d881 100644 --- a/src/runtime/mem_linux.go +++ b/src/runtime/mem_linux.go @@ -170,4 +170,12 @@ func sysMapOS(v unsafe.Pointer, n uintptr) { print("runtime: mmap(", v, ", ", n, ") returned ", p, ", ", err, "\n") throw("runtime: cannot map pages in arena address space") } + + // Disable huge pages if the GODEBUG for it is set. + // + // Note that there are a few sysHugePage calls that can override this, but + // they're all for GC metadata. + if debug.disablethp != 0 { + sysNoHugePageOS(v, n) + } } diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 877d94eef28d85..087d5ebce734a7 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -309,6 +309,7 @@ type dbgVar struct { var debug struct { cgocheck int32 clobberfree int32 + disablethp int32 dontfreezetheworld int32 efence int32 gccheckmark int32 @@ -344,6 +345,7 @@ var dbgvars = []*dbgVar{ {name: "allocfreetrace", value: &debug.allocfreetrace}, {name: "clobberfree", value: &debug.clobberfree}, {name: "cgocheck", value: &debug.cgocheck}, + {name: "disablethp", value: &debug.disablethp}, {name: "dontfreezetheworld", value: &debug.dontfreezetheworld}, {name: "efence", value: &debug.efence}, {name: "gccheckmark", value: &debug.gccheckmark},