рдмрд╛рдЗрдЯреНрд╕ред рдЧреЛрдлрд░ рдЧреЛ рдЗрди: рдЕрдиреБрдХреВрд▓рди рдЬреЛ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ

рдХрдИ рдЧреЛ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдмрд╛рдЗрдЯреНрд╕ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВред рдмрдлрд╝рд░ ред рдЗрд╕рдХрд╛ рдПрдХ рд▓рд╛рдн рдпрд╣ рд╣реИ рдХрд┐ рдпрд╣ рдЖрдкрдХреЛ " рдЫреЛрдЯреЗ рдмрдлрд░ / рдЖрдХрд╛рд░ рдЕрдиреБрдХреВрд▓рди " рдХреЗ рд░реВрдк рдореЗрдВ рдЙрд╕реА рддрд░рд╣ рд╕реЗ рдвреЗрд░ рдкрд░ рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдмрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ:


type Buffer struct { bootstrap [64]byte //        // ...   } 

рдХреЗрд╡рд▓ рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИред рдпрд╣ рдЕрдиреБрдХреВрд▓рди рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ ред


рдЗрд╕ рд▓реЗрдЦ рдХреЗ рдЕрдВрдд рддрдХ, рдЖрдкрдХреЛ рдкрддрд╛ рдЪрд▓ рдЬрд╛рдПрдЧрд╛ рдХрд┐ рдпрд╣ рдЕрдиреБрдХреВрд▓рди рдХреНрдпреЛрдВ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╣рдо рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


рдЬреИрд╕рд╛ рдХрд┐ рдЗрд░рд╛рджрд╛ рдерд╛, "рдЫреЛрдЯреЗ рдмрдлрд░ рдЕрдиреБрдХреВрд▓рди"


рдЖрдЗрдП bytes.Buffer рдХреА рдереЛрдбрд╝реА рд╕рд░рд▓ рдкрд░рд┐рднрд╛рд╖рд╛ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреЗ рд╣реИрдВред bytes.Buffer :


 const smallBufSize int = 64 type Buffer struct { bootstrap [smallBufSize]byte buf []byte } 

рдЬрдм рд╣рдо Buffer рдкрд░ рдХреНрд░рд┐рдпрд╛ рдХрд░рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, Buffer рдХреЙрд▓ рдХрд░реЗрдВред рдЗрд╕рдХреЗ Buffer.Write , рд░рд┐рдХреЙрд░реНрдб рд╣рдореЗрд╢рд╛ buf рдореЗрдВ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЗрд╕ рд░рд┐рдХреЙрд░реНрдб рд╕реЗ рдкрд╣рд▓реЗ, Buffer.grow(n) рдкреНрд░рддреНрдпреЗрдХ рд╕рдорд╛рди рд╡рд┐рдзрд┐ рдХреЗ рдЕрдВрджрд░ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ Buffer.grow(n) , рдЬреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рд╕реНрд▓рд╛рдЗрд╕ рдореЗрдВ рдкрд░реНрдпрд╛рдкреНрдд рдЬрдЧрд╣ рд╣реЛред рдЕрдЧрд▓реЗ n рдмрд╛рдЗрдЯреНрд╕


рд╡рд┐рдХрд╛рд╕ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦ рд╕рдХрддрд╛ рд╣реИ:


 func (b *Buffer) grow(n int) { //         bytes.Buffer. l := len(b.buf) //   Buffer need := n + l have := cap(b.buf) - l if have >= need { b.buf = b.buf[:need] return } if need <= smallBufSize { //     , //   . b.buf = b.bootstrap[:] } else { // growFactor -     . //     need  need*2. newBuf := make([]byte, need, growFactor(need)) copy(newBuf, b.buf) b.buf = newBuf } } 

рдмрдлрд╝рд░.рдЧреНрд░реЛ рдХреЗ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рдорд╛рди


рд╣рдо рдпрд╣ рдзрд╛рд░рдгрд╛ рдмрдирд╛рддреЗ рд╣реИрдВ рдХрд┐ len(b.buf) рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдбреЗрдЯрд╛ рд▓рдВрдмрд╛рдИ рд╣реИ, рдЬрд┐рд╕реЗ рд╕реНрд▓рд╛рдЗрд╕ рдореЗрдВ рдирдП рдмрд╛рдЗрдЯреНрд╕ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП len(b.buf) рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Write рд╣реЛрдЧрд╛ред рдпрд╣ bytes.Buffer рдореЗрдВ рдорд╛рдорд▓рд╛ рдирд╣реАрдВ рд╣реИред рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕реЗ bytes.Buffer , рд▓реЗрдХрд┐рди рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдПрдХ рдорд╣рддреНрд╡рд╣реАрди рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рд╡рд░рдг рд╣реИред




рдпрджрд┐ b рд╕реНрдЯреИрдХ рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдЗрд╕рдХреЗ рдЕрдВрджрд░ bootstrap рдХреЛ рд╕реНрдЯреИрдХ рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╕реНрд▓рд╛рдЗрд╕ b.buf рдЕрддрд┐рд░рд┐рдХреНрдд рдЖрд╡рдВрдЯрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд┐рдирд╛ b рдЕрдВрджрд░ рдореЗрдореЛрд░реА рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред


рдЬрдм grow рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ bootstrap рд╕рд░рдгреА рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рддреЛ рдПрдХ рдирдпрд╛, "рд╡рд╛рд╕реНрддрд╡рд┐рдХ" рд╕реНрд▓рд╛рдЗрд╕ рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬрд╣рд╛рдВ рдкрд┐рдЫрд▓реЗ рд╕реНрдЯреЛрд░реЗрдЬ ("рдЫреЛрдЯреЗ рдмрдлрд░" рд╕реЗ) рддрддреНрд╡реЛрдВ рдХреЛ рдХреЙрдкреА рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЙрд╕рдХреЗ рдмрд╛рдж, Buffer.bootstrap рдЕрдкрдиреА рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХрддрд╛ рдЦреЛ рджреЗрдЧрд╛ред рдпрджрд┐ Buffer.Reset , рддреЛ cap(b.buf) рд╕рдорд╛рди рд░рд╣реЗрдЧрд╛ рдФрд░ bootstrap рд╕рд░рдгреА рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреАред


рд╕реНрдореГрддрд┐ рдвреЗрд░ рдореЗрдВ рднрд╛рдЧ рд░рд╣реА рд╣реИ


рдЖрдЧреЗ рдпрд╣ рдЕрдкреЗрдХреНрд╖рд╛ рдХреА рдЬрд╛рддреА рд╣реИ рдХрд┐ рдкрд╛рдардХ рдХрдо рд╕реЗ рдХрдо рд╕рддрд╣реА рд░реВрдк рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛ рдЬреЛ рдЧреЛ рдореЗрдВ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╕реЗ рдмрдЪрддрд╛ рд╣реИред


рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реНрдерд┐рддрд┐ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:


 func f() *Buffer { var b bytes.Buffer // leak.go:11:6: moved to heap: b return &b // leak.go:12:9: &b escapes to heap } 

рдпрд╣рд╛рдВ b рдХреЛ рдвреЗрд░ рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕рдХрд╛ рдХрд╛рд░рдг b рдХреЛ рд▓реАрдХ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рд╕реВрдЪрдХ рд╣реИ:


 $ go tool compile -m leak.go leak.go:12:9: &b escapes to heap leak.go:11:6: moved to heap: b 

рд╢рдмреНрджрд╛рд╡рд▓реА


рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, "рд▓реАрдХ" рдФрд░ "рдкрд▓рд╛рдпрди" рдХрд╛ рдЙрдкрдпреЛрдЧ рд▓рдЧрднрдЧ рдкрд░реНрдпрд╛рдпрд╡рд╛рдЪреА рд░реВрдк рд╕реЗ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


рд╕рдВрдХрд▓рдХ рдореЗрдВ рд╣реА рдХреБрдЫ рдЕрдВрддрд░ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореВрд▓реНрдп "рд╣реАрдк рд╕реЗ рдмрдЪ", рд▓реЗрдХрд┐рди рдлрд╝рдВрдХреНрд╢рди рдкреИрд░рд╛рдореАрдЯрд░ "рд▓реАрдХрд┐рдВрдЧ рдкрд░рдо рдПрдХреНрд╕" рд╣реИрдВред


рдПрдХ рд▓реАрдХрд┐рдВрдЧ рдкреИрд░рд╛рдореАрдЯрд░ рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдЗрд╕ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд▓рд┐рдП рдкрд╛рд░рд┐рдд рддрд░реНрдХ рдХреЛ рдвреЗрд░ рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рд▓реАрдХрд┐рдВрдЧ рдкреИрд░рд╛рдореАрдЯрд░ рддрд░реНрдХреЛрдВ рдХреЛ рдвреЗрд░ рдореЗрдВ рднрд╛рдЧрдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИред




рдКрдкрд░ рдПрдХ рд╕реНрдкрд╖реНрдЯ рдорд╛рдорд▓рд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛:


 func length() int { var b bytes.Buffer b.WriteString("1") return b.Len() } 

рдпрд╣рд╛рдВ рд╣рдореЗрдВ рдХреЗрд╡рд▓ 1 рдмрд╛рдЗрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд╕рдм рдХреБрдЫ bootstrap рдореЗрдВ рдлрд┐рдЯ рдмреИрдарддрд╛ рд╣реИ, рдмрдлрд░ рд╕реНрд╡рдпрдВ рд╕реНрдерд╛рдиреАрдп рд╣реИ рдФрд░ рдлрд╝рдВрдХреНрд╢рди рд╕реЗ "рдмрдЪ" рдирд╣реАрдВ рдЬрд╛рддрд╛ рд╣реИред рдЖрдк рдЖрд╢реНрдЪрд░реНрдпрдЪрдХрд┐рдд рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдкрд░рд┐рдгрд╛рдо рд╕рдорд╛рди рд╣реЛрдЧрд╛, рдвреЗрд░ рдкрд░ рдЖрд╡рдВрдЯрди b ред



рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:


 BenchmarkLength-8 20000000 90.1 ns/op 112 B/op 1 allocs/op 

рдмреЗрдВрдЪрдорд╛рд░реНрдХ рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ


 package p import ( "bytes" "testing" ) func length() int { var b bytes.Buffer b.WriteString("1") return b.Len() } func BenchmarkLength(b *testing.B) { for i := 0; i < bN; i++ { _ = length() } } 



рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг 112 рдмреА / рдСрдк


рдЬрдм рд░рдирдЯрд╛рдЗрдо N рдмрд╛рдЗрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдЖрд╡рдВрдЯрдирдХрд░реНрддрд╛ рд╕реЗ рдкреВрдЫрддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ N рдмрд╛рдЗрдЯреНрд╕ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдП рдЬрд╛рдПрдВред


рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рд╕рднреА рдкрд░рд┐рдгрд╛рдо GOOS=linux рдФрд░ GOARCH=AMD64 рдХреЗ рд╕рдВрдпреЛрдЬрди рдХреЗ рд▓рд┐рдП рд╣реИрдВред

 package benchmark import "testing" //go:noinline func alloc9() []byte { return make([]byte, 9) } func BenchmarkAlloc9(b *testing.B) { for i := 0; i < bN; i++ { _ = alloc9() } } 

рдпрджрд┐ рдЖрдк рдЪрд▓рддреЗ go test -bench=. -benchmem рдЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд╕рд╛рде go test -bench=. -benchmem :


 BenchmarkAlloc9-8 50000000 33.5 ns/op 16 B/op 1 allocs/op 

9 рдмрд╛рдЗрдЯреНрд╕ рдХрд╛ рдЕрдиреБрд░реЛрдз, 16 рдЖрд╡рдВрдЯрд┐рддред рдЕрдм рдмрд╛рдЗрдЯреНрд╕ рдкрд░ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВред bytes.Buffer :


 fmt.Println(unsafe.Sizeof(bytes.Buffer{})) => 104 

рдЖрдЗрдП $ GOROOT / src / runtime / sizeclasses.go рдХреЛ рджреЗрдЦреЗрдВ :


 // class bytes/obj bytes/span objects tail waste max waste // 1 8 8192 1024 0 87.50% // 2 16 8192 512 0 43.75% // 3 32 8192 256 0 46.88% // 4 48 8192 170 32 31.52% // 5 64 8192 128 0 23.44% // 6 80 8192 102 32 19.07% // 7 96 8192 85 32 15.95% // 8 112 8192 73 16 13.56% // ...  

рдпрд╣ 96 рдмрд╛рдЗрдЯреНрд╕ рдореЗрдВ рдлрд┐рдЯ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, 112 рдХрд╛ рдЪрдпрди рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред




рд▓реЗрдХрд┐рди рдРрд╕рд╛ рдХреНрдпреЛрдВ рд╣реЛ рд░рд╣рд╛ рд╣реИ?


рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ рдФрд░ рдХреНрдпреЛрдВ


рд╕реНрдерд┐рддрд┐ рдХрд╛ рдХреБрдЫ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╢реБрд░реБрдЖрдд рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдореБрджреНрджреЗ рдореЗрдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреНрд░рдЬрдирдирдХрд░реНрддрд╛ рднреА рд╣реИред


рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕реНрдерд╛рди рд╕рд┐рд░реНрдл рдЕрд╕рд╛рдЗрдирдореЗрдВрдЯ b.buf = b.bootstrap[:] ред рдпрд╣ рдХреЛрдб рдмрдЪ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд╛ рдЕрдиреБрдорд╛рди b.bootstrap рдХрд┐ b.bootstrap "рднрд╛рдЧ рд░рд╣рд╛ рд╣реИ", рдФрд░ рдЪреВрдВрдХрд┐ рдпрд╣ рдПрдХ рд╕рд░рдгреА рд╣реИ, рдпрд╣ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рдЕрдВрджрд░ рд╣реА рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╕рднреА b рдХреЛ рдвреЗрд░ рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред


рдпрджрд┐ рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдПрдХ рдЯреБрдХрдбрд╝рд╛ рдерд╛, рдПрдХ рд╕рд░рдгреА рдирд╣реАрдВ, рддреЛ рдРрд╕рд╛ рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗ рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рд╣реА рд╕реНрд▓рд╛рдЗрд╕ рдЕрд╕рд╛рдЗрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдбрд╣реЙрдХ рдЕрдиреБрдХреВрд▓рди рд╣реИ:


 //   ,     , // object      . object.buf1 = object.buf2[a:b] 

рдЙрддреНрддрд░ рдХреНрдпреЛрдВ рдпрд╣ рдЕрдиреБрдХреВрд▓рди рд╕рд░рдгрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдКрдкрд░ рддреИрдпрд╛рд░ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ esc.go # L835-L866 рд╕реЗ рдПрдХ рдирд┐рдЪреЛрдбрд╝ рд╣реИ (рд╕рдВрдкреВрд░реНрдг рдЕрдиреБрдХреВрд▓рди рдХреЛрдб рд╕рдВрджрд░реНрдн рджреНрд╡рд╛рд░рд╛ рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ):


 // Note, this optimization does not apply to OSLICEARR, // because it does introduce a new pointer into b that was not already there // (pointer to b itself). After such assignment, if b contents escape, // b escapes as well. If we ignore such OSLICEARR, we will conclude // that b does not escape when b contents do. 

рдпрд╣рд╛рдВ рдпрд╣ рдзреНрдпрд╛рди рджреЗрдиреЗ рдпреЛрдЧреНрдп рд╣реИ рдХрд┐ рд╕реВрдЪрдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдХреЗ рд▓рд┐рдП "рд▓реАрдХ" рдХреЗ рдХрдИ рд╕реНрддрд░ рд╣реИрдВ, рдЙрдирдореЗрдВ рд╕реЗ рдореБрдЦреНрдп рд╣реИрдВ:


  1. рдСрдмреНрдЬреЗрдХреНрдЯ рд╣реА рдмрдЪ рдЬрд╛рддрд╛ рд╣реИ (b es рдПрд╕реНрдХреЗрдк)ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╣реАрдк рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
  2. рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рддрддреНрд╡ (рдмреА рд╕рд╛рдордЧреНрд░реА рдмрдЪ) рд╕реЗ рдмрдЪ рдЬрд╛рддреЗ рд╣реИрдВред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдкреЙрдЗрдВрдЯрд░реНрд╕ рдХреЛ рднрд╛рдЧрдиреЗ рд╕реЗ рдорд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИред

рдРрд░реЗ рдХреЗ рд╕рд╛рде рдорд╛рдорд▓рд╛ рдЗрд╕ рд▓рд┐рд╣рд╛рдЬ рд╕реЗ рдЦрд╛рд╕ рд╣реИ рдХрд┐ рдЕрдЧрд░ рдПрд░реЗ рд▓реАрдХ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдЙрд╕рдореЗрдВ рдореМрдЬреВрдж рдСрдмреНрдЬреЗрдХреНрдЯ рднреА рд▓реАрдХ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред


рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдЗрд╕ рдмрд╛рдд рдкрд░ рдирд┐рд░реНрдгрдп рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╕реНрдЯреИрдХ рдкрд░ рдХрд┐рд╕реА рд╡рд╕реНрддреБ рдХреЛ рд░рдЦрдирд╛ рд╕рдВрднрд╡ рд╣реИ рдпрд╛ рдирд╣реАрдВ, рдХреЗрд╡рд▓ рдЙрд╕ рдЬрд╛рдирдХрд╛рд░реА рдкрд░ рдирд┐рд░реНрднрд░ рд╣реИ рдЬреЛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд┐рдП рдЧрдП рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╢рд░реАрд░ рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИред Buffer.grow рд╡рд┐рдзрд┐ рд╕реВрдЪрдХ рджреНрд╡рд╛рд░рд╛ b рд▓реЗрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕реЗ рд▓рдЧрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреБрдХреНрдд рд╕реНрдерд╛рди рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдПрдХ рд╕рд░рдгреА рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╣рдо "b escape" рдХреЛ "b contents escape" "b escape" рд╕реЗ рдЕрд▓рдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ "b contents escape" , рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдЕрдзрд┐рдХ рдирд┐рд░рд╛рд╢рд╛рд╡рд╛рджреА рд╣реЛрдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЗрд╕ рдирд┐рд╖реНрдХрд░реНрд╖ рдкрд░ рдЖрдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ b рд╕реНрдЯреИрдХ рдкрд░ рдЬрдЧрд╣ рдХреЗ рд▓рд┐рдП рд╕реБрд░рдХреНрд╖рд┐рдд рдирд╣реАрдВ рд╣реИред


рдЗрд╕рдХреЗ рд╡рд┐рдкрд░реАрдд рдорд╛рди рд▓реЗрдВ рдХрд┐ self-assignment рдкреИрдЯрд░реНрди рд╕рд░рдгрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЙрд╕реА рддрд░рд╣ рд╣рд▓ рдХрд░рддрд╛ рд╣реИ рдЬреИрд╕реЗ рдХрд┐ рдпрд╣ рд╕реНрд▓рд╛рдЗрд╕ рдХреЗ рд▓рд┐рдП рдХрд░рддрд╛ рд╣реИ:


 package example var sink interface{} type bad struct { array [10]byte slice []byte } func (b *bad) bug() { b.slice = b.array[:] // ignoring self-assignment to b.slice sink = b.array // b.array escapes to heap // b does not escape } 

рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╕реНрдЯреИрдХ рдкрд░ b рд▓рдЧрд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рдЖрдкрджрд╛ рдХреЛ рдЬрдиреНрдо рджреЗрдЧрд╛: рдЬрд┐рд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдВрджрд░ b рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЙрд╕реЗ рдмрд╛рд╣рд░ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЬрд┐рд╕ рдореЗрдореЛрд░реА рдХреЛ sink рд╕рдВрджрд░реНрднрд┐рдд рдХрд░реЗрдЧрд╛, рд╡рд╣ рдХрдЪрд░реЗ рд╕реЗ рдЬреНрдпрд╛рджрд╛ рдХреБрдЫ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред


рдПрд░рд┐рдпрд░ рдкреЙрдЗрдВрдЯрд░реНрд╕


рдХрд▓реНрдкрдирд╛ рдХреАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ Buffer рдХреЛ рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рдШреЛрд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛:


 const smallBufSize int = 64 type Buffer struct { - bootstrap [smallBufSize]byte + bootstrap *[smallBufSize]byte buf []byte } 

рдПрдХ рдирд┐рдпрдорд┐рдд рд╕рд░рдгреА рдХреЗ рд╡рд┐рдкрд░реАрдд, рд╕рд░рдгреА рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реВрдЪрдХ Buffer рдЕрдВрджрд░ рд╕рднреА рддрддреНрд╡реЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдЕрдЧрд░ bootstrap рдЖрд╡рдВрдЯрди рдвреЗрд░ рдкрд░ рд╣реЛрддрд╛ рд╣реИ рддреЛ рдвреЗрд░ рдкрд░ Buffer рдЖрд╡рдВрдЯрди рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдПрд╕реНрдХреЗрдк рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╕рдВрднрд╡ рд╣реЛрдиреЗ рдкрд░ рд╕реНрдЯреИрдХ рдкрд░ рдкреЙрдЗрдВрдЯрд░ рдлрд╝реАрд▓реНрдб рдЖрд╡рдВрдЯрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдо рдорд╛рди рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдРрд╕реА Buffer рдкрд░рд┐рднрд╛рд╖рд╛ рдЕрдзрд┐рдХ рд╕рдлрд▓ рд╣реИред


рд▓реЗрдХрд┐рди рдпрд╣ рд╕рд┐рджреНрдзрд╛рдВрдд рдореЗрдВ рд╣реИред рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ, рдПрдХ рд╕рд░рдгреА рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдВрдХреЗрддрдХ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдПрдХ рдирд┐рдпрдорд┐рдд рд╢реНрд░реЗрдгреА рд╕реЗ рдПрдХ рд╕реНрд▓рд╛рдЗрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╣реА рд╢реНрд░реЗрдгреА рдореЗрдВ рдЖрддрд╛ рд╣реИ, рдЬреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рд╣реА рдирд╣реАрдВ рд╣реИред CL133375: cmd / compile / рдЖрдВрддрд░рд┐рдХ / gc: рдПрд╕реНрд╕реЗрдВрдЧреЛ рдореЗрдВ рдПрд░реЗ рд╕реНрд▓рд╛рдЗрд╕ рд╕реЗрд▓реНрдл-рдЕрд╕рд╛рдЗрди рдХреЛ рд╕рдВрднрд╛рд▓рдирд╛ рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдХреЛ рдареАрдХ рдХрд░рдирд╛ рд╣реИред


рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдЗрд╕ рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рдЧреЛ рд╕рдВрдХрд▓рдХ рдореЗрдВ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


рд╢реВрдиреНрдп рдорд╛рди рд╣рдордиреЗ рдЦреЛ рджрд┐рдпрд╛


рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, [64]byte рд╕реЗ *[64]byte рдореЗрдВ рд╕рдВрдХреНрд░рдордг рдХреА рд╕рдорд╕реНрдпрд╛ рд╣реИ: рдЕрдм рд╣рдо bootstrap рдЙрдкрдпреЛрдЧ рдмрд┐рдирд╛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╢реБрд░реВ рдХрд┐рдП рдмрд┐рдирд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ, Buffer рдХрд╛ рдПрдХ рд╢реВрдиреНрдп рдорд╛рди рдЙрдкрдпреЛрдЧреА рд╣реЛрдирд╛ рдмрдВрдж рдХрд░ рджреЗрддрд╛ рд╣реИ, рд╣рдореЗрдВ рдПрдХ рдирд┐рд░реНрдорд╛рддрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


 func NewBuffer() Buffer { return Buffer{bootstrap: new(*[smallBufSize]byte)} } 

рд╣рдо Buffer рд▓реМрдЯрд╛рддреЗ рд╣реИрдВ, рди рдХрд┐ *Buffer , NewBuffer рдХреЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛рдУрдВ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП (рдпрд╣ рдЧреЛ рдореЗрдВ рдмрд╣реБрдд рд░реВрдврд╝рд┐рд╡рд╛рджреА рд╣реИ), рдФрд░ рдЗрд╕ рддрдереНрдп рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрддреЗ рд╣реБрдП рдХрд┐ NewBuffer рд╣рдореЗрд╢рд╛ рдХреЙрд▓ рдХреЗ рд╕реНрдерд╛рди рдкрд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдХреЛрдИ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдирд╣реАрдВ рд╣реЛрдЧреАред


рдПрд╕реНрдХреЗрдк рдХреЙрд▓ рдХреЗ рд╕реНрдерд╛рди рдкрд░ NewBuffer рдмреЙрдбреА рдХреЛ рдПрдореНрдмреЗрдб рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдпрд╣ рд╕рд╛рдмрд┐рдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ new(*[smallBufSize]byte) рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдлреНрд░реЗрдо рдХреЗ рдЬреАрд╡рдирдХрд╛рд▓ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдЗрд╕реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рдРрд╕рд╛ рд╣реИ, рддреЛ рдЖрд╡рдВрдЯрди рд╕реНрдЯреИрдХ рдкрд░ рд╣реЛрдЧрд╛ред


рдЗрдВрдЯреЗрд▓ рдмрд╛рдЗрдЯрдмреБрдл


рдКрдкрд░ рд╡рд░реНрдгрд┐рдд рдЕрдиреБрдХреВрд▓рди Intel-go / bytebuf рдкреИрдХреЗрдЬ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


рдпрд╣ рд▓рд╛рдЗрдмреНрд░реЗрд░реА bytebuf.Buffer рдкреНрд░рдХрд╛рд░ рдХрд╛ рдирд┐рд░реНрдпрд╛рдд рдХрд░рддреА рд╣реИ, рдЬреЛ 99.9% bytes.Buffer рдбреБрдкреНрд▓рд┐рдХреЗрдЯ bytes.Buffer ред bytes.Buffer ред рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдПрдХ рдирд┐рд░реНрдорд╛рддрд╛ ( bytebuf.New ) рдФрд░ рдПрдХ рд╕реВрдЪрдХ рдХреЗ рдмрдЬрд╛рдп рдПрдХ рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ рдПрдХ рд╕рд░рдгреА рдХреА рд╢реБрд░реВрдЖрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдо рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:


 type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)] - bootstrap [64]byte // helps small buffers avoid allocation. + bootstrap *[64]byte // helps small buffers avoid allocation. lastRead readOp // last read operation (for Unread*). } 

рдпрд╣рд╛рдБ bytes.Buffer рд╕рд╛рде рдПрдХ рдкреНрд░рджрд░реНрд╢рди рддреБрд▓рдирд╛ рд╣реИред bytes.Buffer :


 name old time/op new time/op delta String/empty-8 138ns ┬▒13% 24ns ┬▒ 0% -82.94% (p=0.000 n=10+8) String/5-8 186ns ┬▒11% 60ns ┬▒ 1% -67.82% (p=0.000 n=10+10) String/64-8 225ns ┬▒10% 108ns ┬▒ 6% -52.26% (p=0.000 n=10+10) String/128-8 474ns ┬▒17% 338ns ┬▒13% -28.57% (p=0.000 n=10+10) String/1024-8 889ns ┬▒ 0% 740ns ┬▒ 1% -16.78% (p=0.000 n=9+10) name old alloc/op new alloc/op delta String/empty-8 112B ┬▒ 0% 0B -100.00% (p=0.000 n=10+10) String/5-8 117B ┬▒ 0% 5B ┬▒ 0% -95.73% (p=0.000 n=10+10) String/64-8 176B ┬▒ 0% 64B ┬▒ 0% -63.64% (p=0.000 n=10+10) String/128-8 368B ┬▒ 0% 256B ┬▒ 0% -30.43% (p=0.000 n=10+10) String/1024-8 2.16kB ┬▒ 0% 2.05kB ┬▒ 0% -5.19% (p=0.000 n=10+10) name old allocs/op new allocs/op delta String/empty-8 1.00 ┬▒ 0% 0.00 -100.00% (p=0.000 n=10+10) String/5-8 2.00 ┬▒ 0% 1.00 ┬▒ 0% -50.00% (p=0.000 n=10+10) String/64-8 2.00 ┬▒ 0% 1.00 ┬▒ 0% -50.00% (p=0.000 n=10+10) String/128-8 3.00 ┬▒ 0% 2.00 ┬▒ 0% -33.33% (p=0.000 n=10+10) String/1024-8 3.00 ┬▒ 0% 2.00 ┬▒ 0% -33.33% (p=0.000 n=10+10) 

рдЕрдиреНрдп рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА README рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИред


рд╢реВрдиреНрдп рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрдерддрд╛ рдФрд░ рдирд┐рд░реНрдорд╛рдг рдХрд╛рд░реНрдп New рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╛рдзреНрдп рд╣реЛрдиреЗ рдХреЗ рдХрд╛рд░рдг, рдЗрд╕ рдЕрдиреБрдХреВрд▓рди рдХреЛ bytes.Buffer рд▓рд┐рдП рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИред


рдХреНрдпрд╛ рдпрд╣ рддреЗрдЬреА рд╕реЗ bytes.Buffer рдмрдирд╛рдиреЗ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рддрд░реАрдХрд╛ рд╣реИред bytes.Buffer ? рдЬрд╡рд╛рдм рд╣реИ рдирд╣реАрдВред рд▓реЗрдХрд┐рди рдпрд╣ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдПрдХ рдРрд╕реА рд╡рд┐рдзрд┐ рд╣реИ рдЬрд┐рд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рдиреНрдпреВрдирддрдо рдмрджрд▓рд╛рд╡ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред


рдПрд╕реНрдХреЗрдк рдПрдирд╛рд▓рд┐рд╕рд┐рд╕ рдкреНрд▓рд╛рди


рдЕрдкрдиреЗ рд╡рд░реНрддрдорд╛рди рд╕реНрд╡рд░реВрдк рдореЗрдВ, рдЧреЛ рдореЗрдВ рдмрдЪ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдмрд╣реБрдд рдХрдордЬреЛрд░ рд╣реИред рд╕реВрдЪрдХ рдореВрд▓реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рд▓рдЧрднрдЧ рдХреЛрдИ рднреА рдСрдкрд░реЗрд╢рди рдвреЗрд░ рдкрд░ рдЖрд╡рдВрдЯрди рдХреА рдУрд░ рдЬрд╛рддрд╛ рд╣реИ, рднрд▓реЗ рд╣реА рдпрд╣ рдПрдХ рдЙрдЪрд┐рдд рдирд┐рд░реНрдгрдп рди рд╣реЛред


рдореИрдВ рдЬреНрдпрд╛рджрд╛рддрд░ рд╕рдордп рдпрд╣ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдореИрдВ рдЗрди рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреЛрд▓рдВрдЧ / рдЧреЛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рд╕рдорд░реНрдкрд┐рдд рдХрд░рддрд╛ рд╣реВрдВ , рдЗрд╕рд▓рд┐рдП рдЖрдЧрд╛рдореА рд░рд┐рд▓реАрдЬ (1.12) рдореЗрдВ рдХреБрдЫ рд╕реБрдзрд╛рд░ рд╕рдВрднрд╡ рд╣реИрдВред


рдЖрдк рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЗ рдЗрд╕ рд╣рд┐рд╕реНрд╕реЗ рдХреА рдЖрдВрддрд░рд┐рдХ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдФрд░ рд╡рд┐рд╡рд░рдгреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореЗрд░реЗ рдЕрдЧрд▓реЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред рдореИрдВ рдЕрдиреБрд╢рдВрд╕рд╛рдУрдВ рдХрд╛ рдПрдХ рд╕рдореВрд╣ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ рдЬреЛ рдХреБрдЫ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХреЛрдб рдХреЛ рд╕рдВрд░рдЪрдирд╛ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ рддрд╛рдХрд┐ рдЗрд╕рдореЗрдВ рдХрдо рдЕрд╡рд╛рдВрдЫрд┐рдд рд╕реНрдореГрддрд┐ рдЖрд╡рдВрдЯрди рд╣реЛред

Source: https://habr.com/ru/post/hi422447/


All Articles