Как стать автором
Обновить

Комментарии 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. Если, конечно, "горячие пути" смоделированы в тестах.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории