awesome-everything EN
↑ Обратно к восхождению

Производительность

GC: чтение кода и трейсов

Суть Читай реальные Go-сниппеты и строку gctrace, предсказывай поведение GC и выбирай фикс с наибольшим рычагом.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Профиль аллокаций и лог GC — это место, где GC-проблемы действительно диагностируются. Прочитай код и трейс, затем выбери фикс, который senior-инженер сделает первым.

Цель

Отработай цикл, который ты запускаешь в каждом GC-инциденте: прочитай горячий путь, предскажи, откуда мусор, и потянись за фиксом с наибольшим рычагом раньше, чем тронешь хоть одну ручку тюнинга.

Сниппет 1 — растущий срез

func collect(rows []Row) []byte {
    var out []byte                  // nil-срез, нулевая ёмкость
    for _, r := range rows {
        line := fmt.Sprintf("%d,%s\n", r.ID, r.Name)
        out = append(out, line...)  // многократно растёт + копирует
    }
    return out
}
Викторина

На 100k строк откуда берётся бо́льшая часть мусора и какой единственный фикс с наибольшим рычагом?

Сниппет 2 — пул

var bufPool = sync.Pool{New: func() any { return new(bytes.Buffer) }}

func render(w io.Writer, v *View) error {
    b := bufPool.Get().(*bytes.Buffer)
    defer bufPool.Put(b)
    // ... много пишем в b ...
    _, err := w.Write(b.Bytes())
    return err
}
Викторина

В этом коде с пулом буферов есть баг корректности, который нагрузочный тест рано или поздно вскроет. Какой?

Сниппет 3 — строка gctrace

gc 488 @62.1s 39%: 0.41+352+1.1 ms clock, ... 1900->2980->1490 MB, 1990 MB goal, 8 P
Викторина

Читая эту единственную строку gctrace, какое утверждение верно?

Сниппет 4 — escape-анализ

func newPoint(x, y int) *Point {   // возвращает указатель...
    p := Point{x, y}
    return &p                      // ...поэтому p убегает в кучу
}

func sumLocal(x, y int) int {
    p := Point{x, y}               // никогда не убегает
    return p.X + p.Y               // остаётся на стеке
}
Викторина

Какой вызов аллоцирует в куче (добавляя работу GC) и каково общее правило?

Итог

Каждый GC-инцидент читается в коде и трейсах: срезы с нулевой ёмкостью и Sprintf на каждой итерации — классические горячие точки аллокаций; объекты из пула нужно сбрасывать (Reset) перед переиспользованием; строка gctrace с одного взгляда показывает долю GC CPU и время маркировки; а escape-анализ решает стек-vs-куча по тому, переживает ли ссылка свой фрейм. Диагностируй по профилю, чини аллокацию, потом перепрофилируй для подтверждения.

Продолжить восхождение ↑GC: укроти death-spiral
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.