2014-09-04 11 views
13

W golangu wydaje się, że nie ma konstruktorów, ale sugeruje się, aby przydzielić obiekt typu struct za pomocą funkcji, zwykle nazywanej przez "New" + Type Type, na przykładUkład pamięci Golang w porównaniu do C++/C

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

Jednak nie jestem pewien co do układu pamięci urządzenia Go. W C/C++ ten rodzaj kodu oznacza, że ​​zwracasz wskaźnik, który wskazuje obiekt tymczasowy, ponieważ zmienna jest przydzielana na stosie, a zmienna może być koszem po powrocie funkcji. W Golang, czy muszę się martwić takimi rzeczami? Ponieważ Wydaje się, że żaden standard nie pokazuje, jaki rodzaj danych zostanie przydzielony na stosie, a jakie dane zostaną przydzielone na stercie.

Tak jak w Javie, wydaje się, że istnieje określony punkt, w którym podstawowy typ, taki jak int, float zostanie przydzielony na stosie, inny obiekt pochodzący z obiektu zostanie przydzielony na stercie. Czy w golangu jest o tym mowa?

+5

Zostanie przydzielona na stercie. Kompilator Go może wykryć, kiedy obiekt będzie żył poza stosem i automatycznie przydzieli go na stercie. Możesz go zobaczyć, jeśli skompilujesz komendę 'go build -gcflags '-m'', aby zobaczyć decyzje optymalizacyjne. – siritinga

+2

@python: Twoja intuicja miała rację, że nie musisz się o to martwić. W praktyce jest prawdą, że zostanie przydzielony na stercie, ale model pamięci Go jest bardzo prosty i nie musisz w ogóle myśleć o stosach i stertach. Możesz po prostu myśleć o zmiennych. Jeśli weźmiesz adres, Go zagwarantuje, że ten adres jest zawsze ważny, o ile masz na to wskaźnik. Nie powinno mieć znaczenia, jako programista, jak to się dzieje. (oczywiście, może być ciekawie pomyśleć o tym, jak to jest zaimplementowane i jest tam kilka fajnych rzeczy) – joshlf

+0

dziękuję za wszystkie twoje odpowiedzi – python

Odpowiedz

26

Composite Literal section wymienia:

Biorąc adres kompozytowego dosłownych (operatorów §Address) generuje unikalny wskaźnik, na przykład wartości dosłownym jest.

Oznacza to, że wskaźnik zwrócony przez funkcję New będzie ważny (przydzielony na stosie).
Calls:

W wywołaniu funkcji, wartość funkcji i argumenty są oceniane w zwykłej kolejności.
Po ich obliczeniu parametry wywołania są przekazywane do funkcji i wywoływana funkcja rozpoczyna wykonywanie.
Parametry zwracane przez funkcję są przekazywane z powrotem do funkcji wywołującej, gdy funkcja zwraca.

Możesz zobaczyć więcej in this answer i this thread.

Jak wspomniano w „Stack vs heap allocation of structs in Go, and how they relate to garbage collection”:

Warto zauważyć, że słowa «komin» i «kupa» nie pojawia się nigdzie w specyfikacji języka.


W blog post "Escape Analysis in Go" szczegółów co się dzieje, mentioning the FAQ:

Jeśli to możliwe, kompilatory Go przeznaczy zmiennych, które są lokalne dla funkcji w ramce stosu tej funkcji.
Jeśli jednak kompilator nie może dowieść, że zmienna nie jest odwoływana po zwróceniu funkcji, to kompilator musi przydzielić zmienną na stadzie zbierającym śmieci, aby uniknąć zwisających błędów wskaźnika.
Ponadto, jeśli zmienna lokalna jest bardzo duża, rozsądniejsze może być przechowywanie jej na stercie zamiast stosu.

Blog Post dodaje:

Kod, który robi „uciec analizy” mieszka w src/cmd/gc/esc.c.
Pod względem koncepcyjnym próbuje ustalić, czy zmienna lokalna ucieka z bieżącego zakresu; jedyne dwa przypadki, w których do tego dochodzi, to zwracanie adresu zmiennej i jej adres przypisany do zmiennej w zewnętrznym zasięgu.
Jeśli zmienna ulegnie zmianie, musi zostać przydzielona na stercie; w przeciwnym razie można bezpiecznie umieścić go na stosie.

Co ciekawe, dotyczy to również przydziałów na new(T).
Jeśli nie uciekną, zostaną w końcu przydzielone na stosie. Oto przykład, w celu wyjaśnienia sprawy:

var intPointerGlobal *int = nil 

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

    anInt2 := 42 
    intPointerGlobal = &anInt2 

    anInt3 := 5 

    return &anInt3 
} 

Powyżej anInt0 i anInt1 nie uciec, więc są one przydzielane na stosie;
i anInt3 escape i są przydzielane na stercie.


Patrz także „Five things that make Go fast”:

przeciwieństwie do C, która zmusza do wyboru, jeśli wartość będą przechowywane na stercie, poprzez malloc lub na stosie, deklarując ją wewnątrz zakresu tej funkcji Go implementuje optymalizację zwaną analizą ucieczki.

Optymalizacje Go są zawsze włączone domyślnie.
Można wyświetlić analizę ucieczki kompilatora i decyzje dotyczące wstawiania za pomocą przełącznika -gcflags=-m.

Ponieważ analiza ucieczki jest przeprowadzana w czasie kompilacji, a nie w czasie wykonywania, przydział sterty zawsze będzie szybszy niż przydział sterty, bez względu na wydajność twojego śmieciarza.

+1

Nawet jeśli specyfikacja nie wspomina o tym, kompilator wykonuje w swojej analizie ucieczki: './test.go: 11: nowe (int) ucieczki do kupy' – siritinga

+0

@siritinga Rzeczywiście. Zmieniłem odpowiedź, podając więcej szczegółów na temat analizy ucieczki, pochodzących z http://stackoverflow.com/questions/13715237/return-pointer-to-local-struct#comment23436456_13715281 – VonC

+0

to był tylko komentarz. Na koniec nie jest tak łatwo uniknąć używania terminów stos/stos :) – siritinga

Powiązane problemy