"스택"및 "힙"이라는 단어는 언어 사양의 어느 곳에도 나타나지 않습니다. 귀하의 질문은 "... 스택에 선언되었습니다"및 "... 힙에 선언되었습니다"로 표시되지만 Go 선언 구문은 스택 또는 힙에 대해서는 아무 것도 언급하지 않습니다.
기술적으로 모든 질문 구현에 대한 답변을 의존적으로 만듭니다. 실제로, 스택 (고 루틴 당!)과 힙이 있으며 일부는 스택과 힙에 있습니다. 경우에 따라 컴파일러는 엄격한 규칙 ( " new
항상 힙에 할당")을 따르고 다른 경우에는 "탈출 분석"을 수행하여 객체가 스택에 존재할 수 있는지 또는 힙에 할당되어야하는지 결정합니다.
예제 2에서 이스케이프 분석은 구조체 이스케이프에 대한 포인터를 표시하므로 컴파일러는 구조체를 할당해야합니다. 이 경우 Go의 현재 구현은 엄격한 규칙을 따른다고 생각합니다. 즉, 주소가 구조체의 일부에서 가져 오면 구조체가 힙에 간다는 것입니다.
질문 3의 경우 용어에 대해 혼동 될 위험이 있습니다. Go의 모든 것은 가치에 의해 전달되며 참조에 의한 전달은 없습니다. 여기에서 포인터 값을 반환합니다. 포인터의 요점은 무엇입니까? 예제의 다음 수정을 고려하십시오.
type MyStructType struct{}
func myFunction1() (*MyStructType, error) {
var chunk *MyStructType = new(MyStructType)
// ...
return chunk, nil
}
func myFunction2() (MyStructType, error) {
var chunk MyStructType
// ...
return chunk, nil
}
type bigStruct struct {
lots [1e6]float64
}
func myFunction3() (bigStruct, error) {
var chunk bigStruct
// ...
return chunk, nil
}
구조체의 주소가 아닌 구조체를 반환하도록 myFunction2를 수정했습니다. 이제 myFunction1과 myFunction2의 어셈블리 출력을 비교하십시오.
--- prog list "myFunction1" ---
0000 (s.go:5) TEXT myFunction1+0(SB),$16-24
0001 (s.go:6) MOVQ $type."".MyStructType+0(SB),(SP)
0002 (s.go:6) CALL ,runtime.new+0(SB)
0003 (s.go:6) MOVQ 8(SP),AX
0004 (s.go:8) MOVQ AX,.noname+0(FP)
0005 (s.go:8) MOVQ $0,.noname+8(FP)
0006 (s.go:8) MOVQ $0,.noname+16(FP)
0007 (s.go:8) RET ,
--- prog list "myFunction2" ---
0008 (s.go:11) TEXT myFunction2+0(SB),$0-16
0009 (s.go:12) LEAQ chunk+0(SP),DI
0010 (s.go:12) MOVQ $0,AX
0011 (s.go:14) LEAQ .noname+0(FP),BX
0012 (s.go:14) LEAQ chunk+0(SP),BX
0013 (s.go:14) MOVQ $0,.noname+0(FP)
0014 (s.go:14) MOVQ $0,.noname+8(FP)
0015 (s.go:14) RET ,
여기서 myFunction1 출력이 peterSO의 (우수한) 답변과 다르다는 것을 걱정하지 마십시오. 우리는 분명히 다른 컴파일러를 실행하고 있습니다. 그렇지 않으면 * myStructType 대신 myStructType을 반환하도록 myFunction2를 수정 한 것을 참조하십시오. runtime.new에 대한 호출이 없어졌으며 어떤 경우에는 좋은 일입니다. 잠깐만, 여기 myFunction3이 있습니다.
--- prog list "myFunction3" ---
0016 (s.go:21) TEXT myFunction3+0(SB),$8000000-8000016
0017 (s.go:22) LEAQ chunk+-8000000(SP),DI
0018 (s.go:22) MOVQ $0,AX
0019 (s.go:22) MOVQ $1000000,CX
0020 (s.go:22) REP ,
0021 (s.go:22) STOSQ ,
0022 (s.go:24) LEAQ chunk+-8000000(SP),SI
0023 (s.go:24) LEAQ .noname+0(FP),DI
0024 (s.go:24) MOVQ $1000000,CX
0025 (s.go:24) REP ,
0026 (s.go:24) MOVSQ ,
0027 (s.go:24) MOVQ $0,.noname+8000000(FP)
0028 (s.go:24) MOVQ $0,.noname+8000008(FP)
0029 (s.go:24) RET ,
여전히 runtime.new를 호출하지 않으며 실제로 8MB 객체를 값으로 반환합니다. 작동하지만 일반적으로 원하지 않을 것입니다. 여기서 포인터의 요점은 약 8MB 객체를 밀지 않는 것입니다.