Комментарии 6
Можно еще пользоваться флагом -gcflags "-m"
, выводящий, что убегает в кучу. И, хотя escape-analysis постоянно улучшают, иногда можно встретить
// NoEscape hides a pointer from escape analysis. noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input. noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
//go:nosplit
func NoEscape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
return unsafe.Pointer(x ^ 0)
}
Интересно, раз noescape is inlined
, имеет ли смысл //go:nosplit
? Или в нем часть магии?
Да, в нем часть магии. Дело в том, что эта директива отключает добавление кода, в котором производится проверка размера стека и его расширение в случае нехватки.
Я полагал, что при разворачивании inline проверок размера стека не осуществляется?
package main
import "fmt"
func toBeInlined(i,j int) int{
return i + j
}
var g int
var l = 5
var m = 6
func main(){
g = toBeInlined(l, m)
fmt.Println("Hello, world!")
}
Ассемблер:
;*** main.go#13 >func main(){
0x49dea0 65488b0c2528000000 mov rcx, qword ptr gs:[0x28]
0x49dea9 488b8900000000 mov rcx, qword ptr [rcx]
0x49deb0 483b6110 cmp rsp, qword ptr [rcx+0x10]
0x49deb4 0f8685000000 jbe 0x49df3f
0x49deba 4883ec58 sub rsp, 0x58
0x49debe 48896c2450 mov qword ptr [rsp+0x50], rbp
0x49dec3 488d6c2450 lea rbp, ptr [rsp+0x50]
;*** main.go#14 > g = toBeInlined(l, m)
0x49dec8 488b0561530c00 mov rax, qword ptr [main.l]
;*** main.go#6 > return i + j
0x49decf 48030562530c00 add rax, qword ptr [main.m]
;*** main.go#14 > g = toBeInlined(l, m)
0x49ded6 488905c35d1000 mov qword ptr [main.g], rax
;*** main.go#15 > fmt.Println("Hello, world!")
...
Сказать честно, такой код на Go сложно писать и отлаживать, и те же баги, вызванные некорректным переиспользованием одного и того же []byte
из пула, например, похожи на ошибки use-after-free и прочие, которые есть в Си. Поэтому, как мне кажется, если очень хочется написать на Go нагруженный сервис, которому требуется постоянно следить за тем, чтобы не выделять слишком много памяти, то возможно и правда Rust Вам бы подошел лучше.
Согласен. Rust нынче — очень хороший кандидат на рассмотрение, и надо иметь серьезные обоснования, чтобы выбрать не его.
Сказать честно, такой код на Go сложно писать и отлаживать, и те же баги, вызванные некорректным переиспользованием одного и того же []byte из пула, например, похожи на ошибки use-after-free и прочие, которые есть в Си.
Замечу, что большая часть этих проблем ловится при тестировании флагом -race
. Если, конечно, "горячие пути" смоделированы в тестах.
Охота за убегающей памятью в Go на этапе разработки