Sobes.tech
Middle+

Որտե՞ղ է փոփոխականը, երբ այն առանձնացվում է գորուտինում։

sobes.tech AI

Պատասխան AI-ից

Փոփոխականը կարող է հատկացվել ինչպես goroutine-ի stack-ում, այնպես էլ heap-ում: Դա որոշվում է Go կոմպիլյատորի escape analysis (փախուստի վերլուծություն) մեխանիզմով:

Escape analysis-ի հիմնական սկզբունքները՝

  • Եթե կոմպիլյատորը կարող է ապացուցել, որ փոփոխականը ապրում է միայն մեկ ֆունկցիայի կանչի շրջանակում կամ միայն մեկ goroutine-ի stack-ում (այսինքն՝ այն չի հղվում դուրսից), այն հատկացվում է այդ goroutine-ի stack-ին: Սա ավելի արագ է, քանի որ stack-ը ավտոմատ կերպով կառավարվում է և չի պահանջում գարշահոտ հավաքում:
  • Եթե կոմպիլյատորը չի կարող ապացուցել, որ փոփոխականը սահմանափակված է stack-ի մեջ, կամ եթե դրա վրա կան հղումներ դուրսից (օրինակ՝ փոխանցվում է ցույցատիչով մյուս ֆունկցիային, գրանցվում է գլոբալ փոփոխականում, վերադառնում է ցույցատիչով ֆունկցիայից), այն հատկացվում է heap-ում: Heap-ը պահանջում է գարշահոտ հավաքում, ինչը կարող է դանդաղեցնել գործարկումը:

Օրինակ՝ stack-ում հատկացման:

// Փոփոխական 'x'-ը հատկացվում է stack-ում, քանի որ այն օգտագործվում է միայն ֆունկցիայի ներսում:
func exampleStack() int {
	x := 10
	return x
}

Օրինակ՝ heap-ում հատկացման:

// Փոփոխական 'p' (ցույցատիչ դեպի int) և այն ցուցադրվող int-ը կարող են հատկացվել heap-ում:
// Դա տեղի է ունենում, քանի որ ցույցատիչը վերադառնում է ֆունկցիայից և կարող է օգտագործվել դուրս:
func exampleHeap() *int {
	x := 20 // արժեքը 20 կարող է հատկացվել heap-ում
	return &x // վերադարձնում է x փոփոխականի հասցեն
}

Escape analysis-ը տեղի է ունենում կոմպիլյացիայի ժամանակ: Այն կարելի է ստուգել -gcflags "-m" նշանի միջոցով:

// Կոմպիլյացիա՝ escape analysis-ով
go build -gcflags "-m" your_package_name

Կոմպիլյատորի ելքը ցույց կտա, թե որ փոփոխականներն են "escape to heap":

Այսպիսով, փոփոխականի տեղադրումը (stack vs heap) որոշվում է ոչ թե այն բանի վրա, որ փոփոխականը հատկացվում է goroutine-ում, այլ այն բանի, թե ինչպես է Go-ի կոմպիլյատորը վերլուծում նրա կյանքի ցիկլը և տարածքը: