Go 1.14.3 repairs scavenger pacing on coarse clocks
A zero-duration measurement could stop the Windows scavenger from returning memory. Go 1.14.3 adds a fallback and repairs several other implementation boundaries.
A runtime controller can fail when its measurement is too precise for the clock supplying it. Go 1.14.3 includes a repair for a scavenger that often measured its own work as taking zero time on Windows. Feeding that observation into pacing calculations could produce invalid numeric results and leave the scavenger asleep indefinitely. The application did not need to change its allocation behavior to encounter the problem.
Today's maintenance release includes runtime and compiler fixes alongside changes to cgo, go/doc, and math/big. The scavenger repair explains why a patch release can matter even when it introduces no language feature. A feedback calculation inside the implementation can affect the memory behavior of an otherwise ordinary program.
I value Go's ability to keep resource management out of most application code. That makes the runtime's assumptions about clocks and memory pages particularly relevant. Those assumptions determine whether the implementation can provide the behavior that application authors reasonably leave to it.
A zero observation needs a defined interpretation
The scavenger pacing change describes the failure in terms of measurement granularity. Windows time measurements can have a granularity around a millisecond. A scavenging operation can complete within one clock interval, so its start and end measurements can be equal.
Subtracting those readings produces zero even though the operation performed real work. A controller using elapsed time to estimate a work rate cannot treat that number as an exact duration. The change describes the resulting NaNs and invalid pacing values as the reason the Windows scavenger could end up sleeping forever.
The corrected logic handles measured durations of zero or less by returning to an estimate used in Go 1.13. It assumes approximately ten microseconds per physical page. Negative durations are not expected, but the fallback covers them defensively as well. That gives the calculation a usable value when the clock cannot provide one.
This is a specific approximation with a defined scope. It does not pretend to recover the true duration of the operation. The controller uses a conservative estimate to keep making progress when a measurement falls outside the model's valid inputs. Huge pages do not enter that fallback calculation because they could increase the scavenging rate under uncertain conditions.
A related check verifies that a nonzero amount of released memory represents at least one physical page. The change notes that trying to release less than a physical page can still release the whole page on many systems. The runtime must therefore preserve the physical granularity required by the operating system, independently of the granularity used by its timing calculation.
Allocation search state has its own invariant
Another runtime repair concerns the page allocator's cached allocations. The allocator tracks a search address that must point into memory represented by its in-use mapping. The allocToCache path had assumed it could advance that address past the block that supplied the cache.
That advancement could violate the mapped-memory invariant. The corresponding ordinary allocation path had already received a correction, but the cache path still needed the same consideration. The patch closes that gap. Optimizing an allocation path does not remove its obligation to preserve the search state used by later operations.
These two repairs affect different mechanisms. The scavenger needs a meaningful work-duration estimate and valid release granularity. The allocator needs its search address to remain within mapped memory. Describing both as general memory improvements would lose the constraints that explain their failures.
Constant conversion differs from runtime conversion
The compiler correction addresses another boundary between related operations. A refactoring had overlooked that conversions between real numeric types and complex types are permitted for constants when their values are representable. The corresponding conversions are not permitted for nonconstant expressions.
A small declaration makes the constant case concrete.
const realValue = float64(complex(7, 0))
const complexValue = complex128(7)
The compiler repair passes information about whether the source expression is constant into conversion selection. Representability checking still rejects values that cannot fit the destination. The correction therefore restores valid constant behavior while preserving the restriction on nonconstant conversions.
Documentation examples also depend on classification
The release also repairs whole-file example detection. Earlier changes failed to update declaration counts and test-presence information correctly for functions with parameters. That could cause an example file with a helper function to miss classification as a whole-file example.
This matters because documentation tools interpret a source file before presenting it as an example. A helper declaration can change how the file should be shown even when it is not itself the example entry point. Correct bookkeeping is part of preserving the relationship between executable examples and the documentation a reader sees.
I regard these repairs as useful evidence of how much Go's simplicity depends on implementation detail. Clock resolution, allocation metadata, and constant classification each require a precise internal rule. Go 1.14.3 corrects those rules in the existing release line, including the fallback that lets the scavenger continue when a measured duration supplies no usable rate.