Der Go-Compiler verwendet einen Mechanismus der Escape-Analyse: Alle Werte werden standardmäßig im Stack platziert, aber wenn eine Variable den Geltungsbereich "verlässt" (zum Beispiel, wenn ein Zeiger auf eine lokale Variable zurückgegeben wird), wird sie automatisch im Heap platziert.
Das ist wichtig für die Leistung:
Der Compiler versucht zu bestimmen, ob das Objekt im Stack platziert werden kann, aber wenn es implizit die Grenzen der Funktion "überlebt", wird es im Heap platziert.
Beispiel mit Escape:
func NewPoint() *int { a := 42 return &a // Escape zum Heap! }
Beispiel ohne Escape:
func Sum(a, b int) int { c := a + b return c // im Stack }
Um die Diagnose des Compilers zu verwenden, verwenden Sie go build -gcflags='-m', um Details zu sehen:
go build -gcflags='-m' main.go
"Wird ein Objekt im Heap landen, wenn nur sein Wert — nicht der Zeiger — aus der Funktion zurückgegeben wird?"
Oft wird angenommen, dass alle zurückgegebenen Werte "in den Heap gehen". Tatsächlich kann, wenn ein Wert (nicht der Zeiger) zurückgegeben wird, die Variable im Stack verbleiben.
Beispiel:
func F() int { x := 10 return x // Stack-Zuweisung, geht nicht in den Heap }
Geschichte
Bei der massenhaften Erstellung von Strukturen über eine Fabrikfunktion, die Zeiger auf lokale Variablen zurückgibt, stieg der Speicherbedarf und die Belastung des GC sprunghaft an. Es stellte sich heraus: Alle Objekte gingen in den Heap, weil der Zeiger auf die lokale Variable zurückgegeben wurde, obwohl dies vermieden werden konnte, indem der Wert zurückgegeben wurde.
Geschichte
In einem Mikrodienst kam es aufgrund der Übergabe von Zeigern zwischen Goroutinen und deren Rückgabe aus verschiedenen Funktionen dazu, dass viele Objekte vom Stack in den Heap „überliefen“, was die Arbeit verlangsamte und häufige GC-Pausen verursachte.
Geschichte
Ein Entwickler hatte versehentlich ein statisches Array in einem Slice innerhalb einer Funktion gewickelt und einen Zeiger auf das Slice zurückgegeben — und begann bei Lasttests, Speicherlecks zu erfassen. Die Diagnose ergab: Die Variable übertrat nicht die Grenzen der Funktion, aber Go entschied fälschlicherweise, sie aufgrund der indirekten Verwendung im Heap zu platzieren.