This is incorrect. I've written a bunch of ARM firmware in Go and I've seen server applications that use custom allocators for allocation sensitive code.
"Ultimately, though, it sounds like you want a language which has no garbage collection, and Go is not that language. Language constructs will allocate memory in ways that are not immediately obvious, so there is no reasonable way for a Go program to completely manage its own memory."
Of course you can write memory pools and free lists—you can write them in any language—but, like other languages, the GC will still trace them during mark time and there is no safety provided by the language if you return an object to the pool that's still in use, or leak objects by forgetting to reuse them, and so on.
The fact is that programming in Go, for all practical purposes, requires using a garbage collector.
When you manually allocate memory you are naturally responsible for the lifecycle of that memory. In Go you allocate such memory outside the GC to avoid tracing.
The issue, as Ian pointed out, is that it's hard to pinpoint when GC allocations occur. Language constructs allocate in ways that are not immediately obvious.