Go 1.19 Release Notes

Introduction to Go 1.19

The latest Go release, version 1.19, arrives five months after Go 1.18. Most of its changes are in the implementation of the toolchain, runtime, and libraries. As always, the release maintains the Go 1 promise of compatibility. We expect almost all Go programs to continue to compile and run as before.

Changes to the language

There is only one small change to the language, a very small correction to the scope of type parameters in method declarations. Existing programs are unaffected.

Memory Model

The Go memory model has been revised to align Go with the memory model used by C, C++, Java, JavaScript, Rust, and Swift. Go only provides sequentially consistent atomics, not any of the more relaxed forms found in other languages. Along with the memory model update, Go 1.19 introduces new types in the sync/atomic package that make it easier to use atomic values, such as atomic.Int64 and atomic.Pointer[T].

Ports

LoongArch 64-bit

Go 1.19 adds support for the Loongson 64-bit architecture LoongArch on Linux (GOOS=linux, GOARCH=loong64). The implemented ABI is LP64D. Minimum kernel version supported is 5.19.

Note that most existing commercial Linux distributions for LoongArch come with older kernels, with a historical incompatible system call ABI. Compiled binaries will not work on these systems, even if statically linked. Users on such unsupported systems are limited to the distribution-provided Go package.

RISC-V

The riscv64 port now supports passing function arguments and result using registers. Benchmarking shows typical performance improvements of 10% or more on riscv64.

Tools

Doc Comments

Go 1.19 adds support for links, lists, and clearer headings in doc comments. As part of this change, gofmt now reformats doc comments to make their rendered meaning clearer. See “Go Doc Comments” for syntax details and descriptions of common mistakes now highlighted by gofmt. As another part of this change, the new package go/doc/comment provides parsing and reformatting of doc comments as well as support for rendering them to HTML, Markdown, and text.

New unix build constraint

The build constraint unix is now recognized in //go:build lines. The constraint is satisfied if the target operating system, also known as GOOS, is a Unix or Unix-like system. For the 1.19 release it is satisfied if GOOS is one of aix, android, darwin, dragonfly, freebsd, hurd, illumos, ios, linux, netbsd, openbsd, or solaris. In future releases the unix constraint may match additional newly supported operating systems.

Go command

The -trimpath flag, if set, is now included in the build settings stamped into Go binaries by go build, and can be examined using go version -m or debug.ReadBuildInfo.

go generate now sets the GOROOT environment variable explicitly in the generator’s environment, so that generators can locate the correct GOROOT even if built with -trimpath.

go test and go generate now place GOROOT/bin at the beginning of the PATH used for the subprocess, so tests and generators that execute the go command will resolve it to same GOROOT.

go env now quotes entries that contain spaces in the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS, CGO_LDFLAGS, and GOGCCFLAGS variables it reports.

go list -json now accepts a comma-separated list of JSON fields to populate. If a list is specified, the JSON output will include only those fields, and go list may avoid work to compute fields that are not included. In some cases, this may suppress errors that would otherwise be reported.

The go command now caches information necessary to load some modules, which should result in a speed-up of some go list invocations.

Vet

The vet checker “errorsas” now reports when errors.As is called with a second argument of type *error, a common mistake.

Runtime

The runtime now includes support for a soft memory limit. This memory limit includes the Go heap and all other memory managed by the runtime, and excludes external memory sources such as mappings of the binary itself, memory managed in other languages, and memory held by the operating system on behalf of the Go program. This limit may be managed via runtime/debug.SetMemoryLimit or the equivalent GOMEMLIMIT environment variable. The limit works in conjunction with runtime/debug.SetGCPercent / GOGC, and will be respected even if GOGC=off, allowing Go programs to always make maximal use of their memory limit, improving resource efficiency in some cases. See the GC guide for a detailed guide explaining the soft memory limit in more detail, as well as a variety of common use-cases and scenarios. Please note that small memory limits, on the order of tens of megabytes or less, are less likely to be respected due to external latency factors, such as OS scheduling. See issue 52433 for more details. Larger memory limits, on the order of hundreds of megabytes or more, are stable and production-ready.

In order to limit the effects of GC thrashing when the program’s live heap size approaches the soft memory limit, the Go runtime also attempts to limit total GC CPU utilization to 50%, excluding idle time, choosing to use more memory over preventing application progress. In practice, we expect this limit to only play a role in exceptional cases, and the new runtime metric /gc/limiter/last-enabled:gc-cycle reports when this last occurred.

The runtime now schedules many fewer GC worker goroutines on idle operating system threads when the application is idle enough to force a periodic GC cycle.

The runtime will now allocate initial goroutine stacks based on the historic average stack usage of goroutines. This avoids some of the early stack growth and copying needed in the average case in exchange for at most 2x wasted space on below-average goroutines.

On Unix operating systems, Go programs that import package os now automatically increase the open file limit (RLIMIT_NOFILE) to the maximum allowed value; that is, they change the soft limit to match the hard limit. This corrects artificially low limits set on some systems for compatibility with very old C programs using the select system call. Go programs are not helped by that limit, and instead even simple programs like gofmt often ran out of file descriptors on such systems when processing many files in parallel. One impact of this change is that Go programs that in turn execute very old C programs in child processes may run those programs with too high a limit. This can be corrected by setting the hard limit before invoking the Go program.

Unrecoverable fatal errors (such as concurrent map writes, or unlock of unlocked mutexes) now print a simpler traceback excluding runtime metadata (equivalent to a fatal panic) unless GOTRACEBACK=system or crash. Runtime-internal fatal error tracebacks always include full metadata regardless of the value of GOTRACEBACK

Support for debugger-injected function calls has been added on ARM64, enabling users to call functions from their binary in an interactive debugging session when using a debugger that is updated to make use of this functionality.

The address sanitizer support added in Go 1.18 now handles function arguments and global variables more precisely.

Compiler

The compiler now uses a jump table to implement large integer and string switch statements. Performance improvements for the switch statement vary but can be on the order of 20% faster. (GOARCH=amd64 and GOARCH=arm64 only)

The Go compiler now requires the -p=importpath flag to build a linkable object file. This is already supplied by the go command and by Bazel. Any other build systems that invoke the Go compiler directly will need to make sure they pass this flag as well.

The Go compiler no longer accepts the -importmap flag. Build systems that invoke the Go compiler directly must use the -importcfg flag instead.

Assembler

Like the compiler, the assembler now requires the