2014-09-04 12 views
13

In Golang scheint es keine Konstruktoren zu geben, aber es wird vorgeschlagen, dass Sie ein Objekt eines Strukturtyps mit einer Funktion zuweisen, die normalerweise mit "Neu" + TypName bezeichnet wird, zum BeispielGolang-Speicherlayout im Vergleich zu C++/C

func NewRect(x,y, width, height float) *Rect { 
    return &Rect(x,y,width, height) 
} 

Allerdings bin ich mir nicht sicher über das Speicherlayout von Go. In C/C++ bedeutet diese Art von Code, dass Sie einen Zeiger zurückgeben, der auf ein temporäres Objekt verweist, weil die Variable auf dem Stapel zugeordnet ist, und die Variable möglicherweise nach der Rückgabe der Funktion ein Papierkorb ist. Muss ich mich in Golang um so etwas sorgen? Denn es scheint kein Standard zu sein, der angibt, welche Art von Daten auf dem Stack zugewiesen werden und welche Art von Daten auf dem Heap zugewiesen werden.

Wie in Java scheint es einen spezifischen Hinweis darauf zu geben, dass der Basistyp wie int, float auf dem Stapel zugewiesen wird, andere vom Objekt abgeleitete Objekte werden auf dem Heap zugewiesen. Gibt es in Golang eine spezifische Diskussion darüber?

+5

Es wird auf dem Haufen zugeordnet werden. Der Go-Compiler kann erkennen, wenn ein Objekt außerhalb des Stapels lebt, und es automatisch auf dem Heap zuweisen. Sie können es sehen, wenn Sie mit 'go build -gcflags '-m' kompilieren, um die Optimierungsentscheidungen zu sehen. – siritinga

+2

@python: Deine Intuition war richtig, dass du dir keine Sorgen machen musst. In der Praxis ist es richtig, dass es auf dem Heap zugewiesen wird, aber Gos Speichermodell ist sehr einfach und Sie müssen wirklich nicht über Stacks und Heaps nachdenken. Sie können nur über Variablen nachdenken. Wenn Sie die Adresse von etwas annehmen, garantiert Go, dass diese Adresse immer gültig ist, solange Sie einen Zeiger darauf haben. Es sollte dir als Programmierer egal sein, wie das passiert. (obwohl es natürlich interessant sein kann darüber nachzudenken, wie es umgesetzt wird, und es gibt auch einige coole Sachen dort) – joshlf

+0

danke für alle Ihre Jungs Antwort – python

Antwort

26

Die Composite Literal section erwähnt:

die Adresse eines Verbund literal Unter (§Address Operatoren) erzeugt einen eindeutigen Zeiger auf eine Instanz des Werts des Literal.

Das bedeutet, dass der von der New-Funktion zurückgegebene Zeiger ein gültiger (auf dem Stapel zugeordneter) Zeiger ist.
Calls:

In einem Funktionsaufruf werden der Funktionswert und Argumente in der üblichen Reihenfolge ausgewertet.
Nach der Auswertung werden die Parameter des Aufrufs als Wert an die Funktion übergeben und die aufgerufene Funktion beginnt mit der Ausführung.
Die Rückgabeparameter der Funktion werden von Wert an die aufrufende Funktion zurückgegeben, wenn die Funktion zurückgibt.

Sie können mehr in this answer und this thread sehen.

Wie in „Stack vs heap allocation of structs in Go, and how they relate to garbage collection“ erwähnt:

Es ist erwähnenswert, dass die Worte ‚Stapel‘ und ‚Haufen‘ erscheinen nicht überall in der Sprache spec.


Die blog post "Escape Analysis in Go" Details, was passiert, mentioning the FAQ:

Wenn möglich, werden die Go-Compiler Variablen zuweisen, die in dieser Funktion den Stack-Frame auf eine Funktion lokal sind.
Wenn der Compiler jedoch nicht beweisen kann, dass die Variable nicht referenziert wird, nachdem die Funktion zurückgibt, muss der Compiler die Variable auf dem Garbage-Collected-Heap zuweisen, um Zeigerfehler zu vermeiden.
Wenn eine lokale Variable sehr groß ist, ist es möglicherweise sinnvoller, sie auf dem Heap als auf dem Stapel zu speichern.

Der Blog-Eintrag ergänzt:

Der Code, der die „Flucht Analyse“ tut lebt in src/cmd/gc/esc.c.
Konzeptuell versucht es festzustellen, ob eine lokale Variable den aktuellen Bereich verlässt; Die einzigen beiden Fälle, in denen dies geschieht, sind, wenn die Adresse einer Variablen zurückgegeben wird und wenn ihre Adresse einer Variablen in einem äußeren Bereich zugewiesen wird.
Wenn eine Variable entweicht, muss sie auf dem Heap zugewiesen werden; Ansonsten ist es sicher, es auf den Stapel zu legen.

Interessanterweise gilt dies auch für new(T) Zuordnungen.
Wenn sie nicht entkommen, werden sie am Ende auf dem Stapel zugewiesen. Hier ist ein Beispiel zu klären Fragen:

var intPointerGlobal *int = nil 

func Foo() *int { 
    anInt0 := 0 
    anInt1 := new(int) 

    anInt2 := 42 
    intPointerGlobal = &anInt2 

    anInt3 := 5 

    return &anInt3 
} 

Oben, anInt0 und anInt1 nicht entkommen, so dass sie auf dem Stapel zugeordnet;
anInt2 und anInt3 Escape, und sind auf dem Heap zugeordnet.


Siehe auch „Five things that make Go fast“:

Im Gegensatz zu C, die Sie, wenn ein Wert wählen Kräfte auf dem Heap gespeichert wird, über malloc oder auf dem Stapel, indem er erklärt, Im Rahmen der Funktion implementiert Go eine Optimierung, die als Escape-Analyse bezeichnet wird.

Go's Optimierungen sind immer standardmäßig aktiviert.
Sie können die Escape-Analyse des Compilers und die Einfügung von Entscheidungen mit dem Schalter -gcflags=-m sehen.

Da die Escape-Analyse zur Kompilierungszeit ausgeführt wird und keine Laufzeit besteht, ist die Stapelzuweisung immer schneller als die Heap-Zuweisung, unabhängig davon, wie effizient Ihr Garbage Collector ist.

+1

Auch wenn die Spezifikation es nicht erwähnt, tut der Compiler in seiner Escape-Analyse: './test.go: 11: new (int) escape to haufen' – siritinga

+0

@siritinga In der Tat. Ich habe die Antwort mit mehr Details zur Escape-Analyse bearbeitet, kommend von http://stackoverflow.com/questions/13715237/return-pointer-to-local-struct#comment23436456_13715281 – VonC

+0

es war nur ein Kommentar. Am Ende ist es nicht so einfach zu vermeiden, Heap/Stack-Begriffe zu verwenden :) – siritinga

Verwandte Themen