On May 7, 2022, the Go 1.19 development branch entered the new feature freeze phase, which means that only bugs can be fixed and no new features can be added to Go 1.19. As the previous version of Go 1.18 was delayed by one month due to the introduction of generic changes, this directly led to a shortened development cycle for Go 1.19.

Although the development cycle is nearly a month shorter, Go 1.19 is still on track for an August 2022 release. And the first beta of Go 1.19 was released early yesterday morning. What are the important changes in Go 1.19, I’ll take you through this article for a first look.

Version feature changes are subject to final release! This article is only a preview and will not go into too much detail. We will talk about the details after the official release of Go 1.19.

Fixes for generic issues

Although the Go core team put a lot of effort into Go 1.18 generics, there are still known innate limitations in this piece of Go 1.18 release of generics, as well as some problems found gradually afterwards, and Go 1.19 version will continue to polish Go generics, and focus on fixing the generic issues found in Go 1.18. Currently there are about 5-6 generic issues to be fixed in Go 1.19 development release. The possibility of liberalizing some of the generalization constraints talked about earlier is not expected to be fulfilled in Go 1.19.

What is certain, however, is that Go 1.19 will include a fix for generics in the Go syntax specification.

Old description:

The scope of an identifier denoting a type parameter of a function or declared by a method receiver is the function body and all parameter lists of the function.

New description:

The scope of an identifier denoting a type parameter of a function or declared by a method receiver starts after the function name and ends at the end of the function body.

Such a change allows the source code that would have compiled with an error under the current version of the Go compiler (Go 1.18.x) to compile properly in Go 1.19.

1
2
type T[T any] struct {}
func (T[T]) m() {} // error: T is not a generic type

Revising the Go memory model

Revising the Go memory model.

The Go memory model is one of the most abstract pieces of Go documentation, bar none! As Go has evolved, the original Go memory model description was less formal in many places and lacked descriptions of some synchronization mechanisms, such as atomic.

This revision, which refers to Hans-J. Boehm and Sarita V. Adve in “Foundations of the C++ Concurrency Memory Model, (PLDI 2008)” describe the C++ memory model in a way that gives a more formal overall description of the Go memory model, adding a more formal description of multiword competing states, runtime.SetFinalizer, more sync types, atomic operations, and compiler optimizations.

Revising the go doc comment format

Go has the built-in ability to extract comments directly into package documentation. This is different from other languages that generate documentation via third-party tools. go doc comment provides a great convenience for Gopher. However, go doc comment was designed in 2009 and is somewhat outdated. There is insufficient support for many presentation forms or lack of more precise formatting descriptions. Russ Cox led a revision of go doc comment this time, adding support for hyperlinks, lists, headings, standard library API references, and other formatting, and the revised go doc comment is not markdown syntax, but borrows from markdown syntax, and is compatible with the old comment format. Here are some rendered images of the new doc comment provided by Russ Cox.

go doc comment format

go doc comment format

go doc comment format

Also, the Go team provides the go/doc/comment package, which gopher uses to easily parse go doc comments.

runtime.SetMemoryLimit

In Go 1.19, a new runtime.SetMemoryLimit function was introduced along with a GOMEMLIMIT environment variable. With this memory soft limit, the Go runtime will attempt to maintain this memory limit by limiting the size of the heap and by returning memory more aggressively to the underlying os to try to prevent Go programs from being killed for allocating too much heap and exceeding the system memory resource limit.

The default memory limit is math.MaxInt64. Once the limit is set by SetMemoryLimit, the go runtime will respect this memory limit and keep the total size of memory controlled by the go runtime under the limit by adjusting the GC recovery frequency and returning the memory to os in a timely manner.

Note: The limit is on the total amount of memory controlled by the go runtime, but not on the memory requested by the developer from os (e.g., via mmap). The details of the limit can be found in the proposal design document.

Also note: the limit does not eliminate 100% of the out-of-memory cases.

Go 1.19 will raise the open file limit by default at startup

Upon investigation, some systems set an artificial soft limit on the number of open files, mainly for compatibility with code that uses select and its hard-coded maximum file descriptor (limited by the size of fd_set). Usually the limit is 1024, some are smaller, e.g. 256, so that even simple programs like gofmt can easily encounter an open file descriptor overload error when they traverse a file tree in parallel.

Go does not use select, so it should not be affected by these limits. So for go programs that import os packages, Go will raise these limits by default in 1.19 to hard limit.

Go 1.19 race detector will be upgraded to version v3 of the thread sanitizer

The upgraded new race detector will have 1.5x-2x better race detection performance compared to the previous version, half the memory overhead, and no upper limit on the number of goroutines.

The thread sanitizer detects how data contention works: it records information about each memory access and detects whether there is contention between threads for that piece of memory. Based on this principle, we also know that once race detection is enabled, the execution efficiency of Go programs will be greatly affected and the running overhead will increase significantly. v3 thread sanitizer has been optimized, but the overall impact on the program is still there and still significant.

Go 1.19 adds “unix” build tag

Go 1.19 will add the “unix” build tag.

1
//go:build unix

Equivalent to:

1
//go:build aix || linux || darwin || dragonfly || freebsd || openbsd || netbsd || solaris

Note, however, that “*_unix.go” retains its original semantics and cannot be recognized. so that it is backwards compatible with existing files. This is especially true for use outside of the go standard library.

Some changes to the standard library

net package will use EDNS

In Go 1.19, the net package will use EDNS to increase the size of DNS packets to comply with modern DNS standards and implementations. This should help with some DNS server issues.

flag package adds TextVar function

Go flag package adds TextVar function, so that the flag package can be integrated with any Go type that implements encoding.Text{Marshaler,Unmarshaler}. For example.

1
2
flag.TextVar(&ipaddr, "ipaddr", net.IPv4(192, 168, 0, 1), "what server to connect to?") // with net.IPv4 type
flag.TextVar(&start, "start", time.Now(), "when should we start processing?") // with the time.Time type

Other

  • On linux, Go officially supports 64-bit loong cpu architecture (GOOS=linux, GOARCH=loong64).
  • In the case where Go GC goes into a periodic GC loop when the Go application is idle (once every 2 minutes), the Go runtime will now schedule fewer GC worker goroutines on idle OS threads, reducing the usage of os resources by the Go application when idle.
  • Go runtime will allocate the initial goroutine stack based on the goroutine’s historical average stack usage, avoiding up to 2x the wasted goroutine stack space for some goroutines.
  • sync/atomic package adds new advanced atomic types Bool, Int32, Int64, Uint32, Uint64, Uintptr and Pointer to improve the experience.
  • Go 1.19 Go compiler re-implemented switch statements for large integer numbers and string types using jump tables, improving performance by about 20% on average.

Summary

Compared to Go 1.18, Go 1.19 is indeed a “minor release”. But Go 1.19’s updates to the memory model, the addition of SetMemoryLimit, the revision of the go doc comment, and the continued polishing of go runtime can still generate a little “excitement” among gophers, especially The addition of SetMemoryLimit will improve the situation of Go applications being killed due to untimely GC, let’s wait and see.

The milestone for Go 1.19 is here, and all features and fixes can be seen in that milestone.