ݺߣ

ݺߣShare a Scribd company logo
Управление памятью в GO
План вебинара:
1. Адресное пространство процесса в Linux. Основы управления памятью в
современных ОС.
2. Управление памятью в GO.
3. Оптимизация GO программ. Toolchain и примеры. Cgo.
Адресное пространство процесса в Linux
Адресное пространство процесса в Linux. Stack
- LIFO структура данных.
- Ограничен ОС.
- Элемент данных - stack frame.
Представляет собой память под
локальные переменные, аргументы
и возвращаемые значения функции.
- Размер stack frame'а известен на
этапе компиляции, количество - нет.
- Память очищается автоматически.
Адресное пространство процесса в Linux. Heap
- произвольный доступ
- ОС не ограничивает размер
- размер не известен на этапе компиляции, нужно запрашивать память у ОС
- нет автоматической очистки
Адресное пространство процесса в Linux. Heap
Запросить память в linux
можно:
1. brk (sbrk)
2. mmap
Адресное пространство процесса в Linux.
Stack VS Heap
Stack Heap
Есть ограничения по максимальному размеру Нет ограничений по максимальному размеру
Статичен, размер stack frame'а известен на этапе
компиляции
Хранение данных размер которых не известен на
этапе компиляции
Функция "видит" память только своего stack frame Произвольный доступ (из разных функций, потоков
и даже процессов)
Автоматический менеджмент памяти Нужно подчищать (или переиспользовать) память:
- ручное управление (malloc/free)
- полуавтоматическое управление (unique_ptr,
shared_ptr)
- автоматическое управление (garbage collection)
На практике куча нужна если:
- функция хочет видеть данные аллоцированные в другой функции
- имеем дело с данными динамического размера
- имеем дело с данными большого размера
- данные "шарятся" между потоками
Адресное пространство процесса в Linux.
Stack VS Heap
Управление памятью в GO. Аллокатор
Используется свой аллокатор tcmalloc:
- mmap (not brk)
- память под stack горутины на самом деле выделяется в heap
- используется garbage collector
Управление памятью в GO. Heap тормозит?
Нет! Тормозит gc:
- должен знать о всей памяти выделяемой на heap'е, выполнять обход этой
памяти
- полностью останавливать программу для очистки памяти (STW)
- сохранять инвариант
- бороться с фрагментацией
Управление памятью в GO. А можно ли управлять?
int *mul2(int x) {
int multiplier = 2; // allocated
on stack
int *result =
malloc(sizeof(int)); // allocated on heap
*result = x * multiplier;
return result;
}
func mul2(x int32) *int32 {
var multiplier int32 = 2 //
allocated on stack
result := x * multiplier //
allocated on heap
return &result
}
Управление памятью в GO. А можно ли управлять?
В GO компилятор сам решает где аллоцировать переменную, он действует
согласно набору эвристик - escape analysis. Используя эти правила можно
заставить компилятор GO аллоцировать память там где нам надо.
Оптимизация. Toolchain
Кун-фу оптимизации:
- локализовать "горячее" место - pprof
- обеспечить повторяемость, тестируемость гипотез - go benchmark
- провести анализ кода - escape analysis
- ?????
- PROFIT!
"Преждевременная оптимизация — корень всех зол" - Дональд Кнут.
Оптимизация. Toolchain. Pprof
Можно профилировать тесты либо добавить к себе pprof сервер.
Профилирование по памяти - показывает где и сколько аллоцируется памяти
в heap'е. Профилирование производительности может подтвердить что
аллокации замедляют нашу программу.
Оптимизация. Toolchain. GO benchmark
Позволяют обеспечить повторяемость сценария который мы хотим
оптимизировать. Показывает сколько процессорного времени и аллокаций
было затрачено на одну итерацию бенчмарка.
```bash
go test . -bench=. -benchmem
```
Оптимизация. Toolchain. Escape Analysis
Объясняет почему компилятор GO аллоцировал память так а не иначе.
```bash
go test . -gcflags="-m -m"
```
Оптимизация. Примеры. Копирование структуры
type S struct {
a, b, c int64
d, e, f string
g, h, i float64
}
func byPointer() *S {
return &S{
a: 1, b:
1, c: 1,
e: "foo",
f: "foo",
g: 1.0,
h: 1.0, i: 1.0,
}
}
BenchmarkMemoryHeap
41.43 ns/op 96 B/op 1 allocs/op
func BenchmarkMemoryHeap(b *testing.B) {
var s *S
for i := 0; i < b.N; i++ {
s =
byPointer()
}
_ = fmt.Sprintf("%v", s.a)
}
func byCopy() S {
return S{
a: 1, b: 1,
c: 1,
e: "foo",
f: "foo",
g: 1.0, h:
1.0, i: 1.0,
}
}
func BenchmarkMemoryStack(b *testing.B) {
var s S
for i := 0; i < b.N; i++ {
s = byCopy()
}
_ = fmt.Sprintf("%v", s.a)
}
BenchmarkMemoryStack
5.154 ns/op 0 B/op 0 allocs/op
func BenchmarkMemoryHeap2(b *testing.B) {
for i := 0; i < b.N; i++ {
s :=
byPointer()
if s.a != 1 {
panic("a!=1")
}
}
}
BenchmarkMemoryHeap2-4
5.060 ns/op 0 B/op 0 allocs/op
Оптимизация. Примеры. Строки
type PackageType string
const (
TypeControl = "control"
TypeData = "data"
TypeUnknown = "unknown"
)
type RawPackage struct {
typ []byte
}
func ParseType(p *RawPackage) PackageType {
strType := string(p.typ)
switch strType {
case TypeControl, TypeData:
return
PackageType(strType)
default:
return
TypeUnknown
}
}
func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ {
typ :=
ParseType(testPackages[i % 3])
runtime.KeepAlive(typ)
}
}
BenchmarkParse
16.44 ns/op 5 B/op
1 allocs/op
var (
TypeControlBytes = []byte("control")
TypeDataBytes = []byte("data")
)
func ParseTypeNoAlloc(p *RawPackage) PackageType {
if bytes.Compare(p.typ, TypeControlBytes)
== 0 {
return TypeControl
}
if bytes.Compare(p.typ, TypeDataBytes) == 0
{
return TypeData
}
return TypeUnknown
}
func BenchmarkParseNoAlloc(b *testing.B) {
for i := 0; i < b.N; i++ {
tp :=
ParseTypeNoAlloc(testPackages[i % 3])
runtime.KeepAlive(tp)
BenchmarkParseNoAlloc
8.699 ns/op 0 B/op
0 allocs/op
Оптимизация. Примеры. Строки
func ExternalLibFunc(typ string) {
}
func BenchmarkExternal(b *testing.B) {
var str string
for i := 0; i < b.N; i++ {
str =
string(testPackages[i % 3].typ)
ExternalLibFunc(str)
}
}
BenchmarkExternal
14.74 ns/op 5 B/op 1 allocs/op
func (p *RawPackage) TypeUnsafe() string {
return
*(*string)(unsafe.Pointer(&p.typ))
}
func BenchmarkExternalNoAlloc(b *testing.B) {
var str string
for i := 0; i < b.N; i++ {
str = testPackages[i %
3].TypeUnsafe()
ExternalLibFunc(str)
}
}
BenchmarkExternalNoAlloc
1.366 ns/op 0 B/op 0 allocs/op
Оптимизация. Примеры. Контейнеры
func ManualBenchmark(f func(), benchName string) {
iterCnt := 10_000
startMs := &runtime.MemStats{}
runtime.ReadMemStats(startMs)
startTime := time.Now().UnixNano()
for i := 0; i < iterCnt; i++ {
f()
}
endTime := time.Now().UnixNano()
endMs := &runtime.MemStats{}
runtime.ReadMemStats(endMs)
fmt.Printf(
"%s %d ns/op %d b/op %d
allocs/op n",
benchName,
(endTime-startTime)/int64(iterCnt),
(endMs.HeapAlloc-
startMs.HeapAlloc)/uint64(iterCnt),
(endMs.Mallocs-
startMs.Mallocs)/uint64(iterCnt),
)
}
Оптимизация. Примеры. Контейнеры
type Storage struct {
data []interface{}
}
func (s *Storage) Add(el int) {
s.data = append(s.data, el)
}
var nums = []int{3, 2, 20, 5}
ManualBenchmark(func() {
intStorage :=
&Storage{}
for _, v := range
nums {
intStorage.Add(v)
}
}, "DefaultStorageBenchmark")
DefaultStorageBenchmark
208 ns/op 112 b/op 3 allocs/op
type IntStorage struct {
data []int
}
func (s *IntStorage) Add(el int) {
s.data = append(s.data, el)
}
ManualBenchmark(func() {
intStorage :=
&IntStorage{}
for _, v := range nums {
intStorage.Add(v)
}
}, "IntStorageBenchmark")
IntStorageBenchmark
104 ns/op 56 b/op 3 allocs/op
Оптимизация. Примеры. Контейнеры
int = int64 (для 64битой машины)
SizeOf(int) = 64 (bit) = 8 (byte)
interface{}
type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}
SizeOf(interface{}) = 128 (bit) = 16 (byte)
go run -gcflags=-G=3 main.go
Оптимизация. Примеры. Контейнеры
type genericStorage[T comparable] struct
{
data []T
}
func (s *genericStorage[T]) Add(el T) {
s.data = append(s.data,
el)
}
ManualBenchmark(func() {
intStorage :=
&genericStorage[int]{}
for _, v := range nums {
intStorage.Add(v)
}
}, "GenericStorageBenchmark")
DefaultStorageBenchmark
208 ns/op 112 b/op 3 allocs/op
IntStorageBenchmark
104 ns/op 56 b/op 3 allocs/op
GenericStorageBenchmark
103 ns/op 56 b/op 3 allocs/op
Оптимизация. Бонус
А что если Cgo? Как быть с утечками?
Ответ: еще одна тулза - Valgrind!

More Related Content

What's hot (20)

ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
Alexey Paznikov
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Mikhail Kurnosov
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Mikhail Kurnosov
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Alexey Paznikov
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Mikhail Kurnosov
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
Mikhail Kurnosov
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Alexey Paznikov
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Mikhail Kurnosov
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
Alexey Paznikov
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Alexey Paznikov
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python Meetup
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
victor-yastrebov
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
it-people
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)
Mikhail Kurnosov
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
Alexey Paznikov
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Yauheni Akhotnikau
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
Alexey Paznikov
Методы поиска уязвимостей
Методы поиска уязвимостейМетоды поиска уязвимостей
Методы поиска уязвимостей
solertia
Методы поиска уязвимостей в программах
Методы поиска уязвимостей в программахМетоды поиска уязвимостей в программах
Методы поиска уязвимостей в программах
Vasiliy Shapovalov
Intel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиIntel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибками
Tatyanazaxarova
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
Alexey Paznikov
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Mikhail Kurnosov
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Mikhail Kurnosov
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Кулагин И.И., Пазников А.А., Курносов М.Г. Оптимизация информационных обменов...
Alexey Paznikov
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Семинар 3. Многопоточное программирование на OpenMP (часть 3)
Mikhail Kurnosov
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
Mikhail Kurnosov
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Лекция 2. Коллективные операции в MPI. Параллельные алгоритмы случайного блуж...
Alexey Paznikov
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Mikhail Kurnosov
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...
Alexey Paznikov
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обменыЛекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Лекция 1. Основные понятия стандарта MPI. Дифференцированные обмены
Alexey Paznikov
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python Meetup
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
victor-yastrebov
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
«Память и Python. Что надо знать для счастья?» Алексей Кузьмин, ЦНС
it-people
Векторизация кода (семинар 1)
Векторизация кода (семинар 1)Векторизация кода (семинар 1)
Векторизация кода (семинар 1)
Mikhail Kurnosov
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
Alexey Paznikov
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Yauheni Akhotnikau
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисленияПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
ПВТ - осень 2014 - лекция 1 - Введение в параллельные вычисления
Alexey Paznikov
Методы поиска уязвимостей
Методы поиска уязвимостейМетоды поиска уязвимостей
Методы поиска уязвимостей
solertia
Методы поиска уязвимостей в программах
Методы поиска уязвимостей в программахМетоды поиска уязвимостей в программах
Методы поиска уязвимостей в программах
Vasiliy Shapovalov
Intel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиIntel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибками
Tatyanazaxarova

Similar to Управление памятью в GO (20)

Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
Andrey Karpov
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Ontico
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
Computer Science Club
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Fwdays
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
Haskell Lite - presentation for DevDay about Haskell language
Haskell Lite - presentation for DevDay about Haskell languageHaskell Lite - presentation for DevDay about Haskell language
Haskell Lite - presentation for DevDay about Haskell language
Alexander Granin
Haskell
HaskellHaskell
Haskell
DevDay
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?
Andrey Karpov
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
etyumentcev
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
Eugeniy Tyumentcev
Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...
Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...
Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...
Ontico
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Mikhail Kurnosov
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
Mikhail Kurnosov
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
Mikhail Kurnosov
Parallel STL
Parallel STLParallel STL
Parallel STL
Evgeny Krutko
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормоза
Alexander Shigin
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
Alexey Paznikov
Профайлинг.
Профайлинг. Профайлинг.
Профайлинг.
Nikita Romanov
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
Andrey Karpov
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Ontico
20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov20130429 dynamic c_c++_program_analysis-alexey_samsonov
20130429 dynamic c_c++_program_analysis-alexey_samsonov
Computer Science Club
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Fwdays
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
Haskell Lite - presentation for DevDay about Haskell language
Haskell Lite - presentation for DevDay about Haskell languageHaskell Lite - presentation for DevDay about Haskell language
Haskell Lite - presentation for DevDay about Haskell language
Alexander Granin
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?
Andrey Karpov
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
etyumentcev
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
Eugeniy Tyumentcev
Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...
Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...
Обработка данных в RTB - быстро, дешево и на 98% точно, Павел Калайдин (RuTar...
Ontico
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Mikhail Kurnosov
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
Mikhail Kurnosov
Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)Лекция 7. Стандарт OpenMP (подолжение)
Лекция 7. Стандарт OpenMP (подолжение)
Mikhail Kurnosov
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...
Alexey Paznikov

Управление памятью в GO

  • 2. План вебинара: 1. Адресное пространство процесса в Linux. Основы управления памятью в современных ОС. 2. Управление памятью в GO. 3. Оптимизация GO программ. Toolchain и примеры. Cgo.
  • 4. Адресное пространство процесса в Linux. Stack - LIFO структура данных. - Ограничен ОС. - Элемент данных - stack frame. Представляет собой память под локальные переменные, аргументы и возвращаемые значения функции. - Размер stack frame'а известен на этапе компиляции, количество - нет. - Память очищается автоматически.
  • 5. Адресное пространство процесса в Linux. Heap - произвольный доступ - ОС не ограничивает размер - размер не известен на этапе компиляции, нужно запрашивать память у ОС - нет автоматической очистки
  • 6. Адресное пространство процесса в Linux. Heap Запросить память в linux можно: 1. brk (sbrk) 2. mmap
  • 7. Адресное пространство процесса в Linux. Stack VS Heap Stack Heap Есть ограничения по максимальному размеру Нет ограничений по максимальному размеру Статичен, размер stack frame'а известен на этапе компиляции Хранение данных размер которых не известен на этапе компиляции Функция "видит" память только своего stack frame Произвольный доступ (из разных функций, потоков и даже процессов) Автоматический менеджмент памяти Нужно подчищать (или переиспользовать) память: - ручное управление (malloc/free) - полуавтоматическое управление (unique_ptr, shared_ptr) - автоматическое управление (garbage collection)
  • 8. На практике куча нужна если: - функция хочет видеть данные аллоцированные в другой функции - имеем дело с данными динамического размера - имеем дело с данными большого размера - данные "шарятся" между потоками Адресное пространство процесса в Linux. Stack VS Heap
  • 9. Управление памятью в GO. Аллокатор Используется свой аллокатор tcmalloc: - mmap (not brk) - память под stack горутины на самом деле выделяется в heap - используется garbage collector
  • 10. Управление памятью в GO. Heap тормозит? Нет! Тормозит gc: - должен знать о всей памяти выделяемой на heap'е, выполнять обход этой памяти - полностью останавливать программу для очистки памяти (STW) - сохранять инвариант - бороться с фрагментацией
  • 11. Управление памятью в GO. А можно ли управлять? int *mul2(int x) { int multiplier = 2; // allocated on stack int *result = malloc(sizeof(int)); // allocated on heap *result = x * multiplier; return result; } func mul2(x int32) *int32 { var multiplier int32 = 2 // allocated on stack result := x * multiplier // allocated on heap return &result }
  • 12. Управление памятью в GO. А можно ли управлять? В GO компилятор сам решает где аллоцировать переменную, он действует согласно набору эвристик - escape analysis. Используя эти правила можно заставить компилятор GO аллоцировать память там где нам надо.
  • 13. Оптимизация. Toolchain Кун-фу оптимизации: - локализовать "горячее" место - pprof - обеспечить повторяемость, тестируемость гипотез - go benchmark - провести анализ кода - escape analysis - ????? - PROFIT! "Преждевременная оптимизация — корень всех зол" - Дональд Кнут.
  • 14. Оптимизация. Toolchain. Pprof Можно профилировать тесты либо добавить к себе pprof сервер. Профилирование по памяти - показывает где и сколько аллоцируется памяти в heap'е. Профилирование производительности может подтвердить что аллокации замедляют нашу программу.
  • 15. Оптимизация. Toolchain. GO benchmark Позволяют обеспечить повторяемость сценария который мы хотим оптимизировать. Показывает сколько процессорного времени и аллокаций было затрачено на одну итерацию бенчмарка. ```bash go test . -bench=. -benchmem ```
  • 16. Оптимизация. Toolchain. Escape Analysis Объясняет почему компилятор GO аллоцировал память так а не иначе. ```bash go test . -gcflags="-m -m" ```
  • 17. Оптимизация. Примеры. Копирование структуры type S struct { a, b, c int64 d, e, f string g, h, i float64 } func byPointer() *S { return &S{ a: 1, b: 1, c: 1, e: "foo", f: "foo", g: 1.0, h: 1.0, i: 1.0, } } BenchmarkMemoryHeap 41.43 ns/op 96 B/op 1 allocs/op func BenchmarkMemoryHeap(b *testing.B) { var s *S for i := 0; i < b.N; i++ { s = byPointer() } _ = fmt.Sprintf("%v", s.a) } func byCopy() S { return S{ a: 1, b: 1, c: 1, e: "foo", f: "foo", g: 1.0, h: 1.0, i: 1.0, } } func BenchmarkMemoryStack(b *testing.B) { var s S for i := 0; i < b.N; i++ { s = byCopy() } _ = fmt.Sprintf("%v", s.a) } BenchmarkMemoryStack 5.154 ns/op 0 B/op 0 allocs/op func BenchmarkMemoryHeap2(b *testing.B) { for i := 0; i < b.N; i++ { s := byPointer() if s.a != 1 { panic("a!=1") } } } BenchmarkMemoryHeap2-4 5.060 ns/op 0 B/op 0 allocs/op
  • 18. Оптимизация. Примеры. Строки type PackageType string const ( TypeControl = "control" TypeData = "data" TypeUnknown = "unknown" ) type RawPackage struct { typ []byte } func ParseType(p *RawPackage) PackageType { strType := string(p.typ) switch strType { case TypeControl, TypeData: return PackageType(strType) default: return TypeUnknown } } func BenchmarkParse(b *testing.B) { for i := 0; i < b.N; i++ { typ := ParseType(testPackages[i % 3]) runtime.KeepAlive(typ) } } BenchmarkParse 16.44 ns/op 5 B/op 1 allocs/op var ( TypeControlBytes = []byte("control") TypeDataBytes = []byte("data") ) func ParseTypeNoAlloc(p *RawPackage) PackageType { if bytes.Compare(p.typ, TypeControlBytes) == 0 { return TypeControl } if bytes.Compare(p.typ, TypeDataBytes) == 0 { return TypeData } return TypeUnknown } func BenchmarkParseNoAlloc(b *testing.B) { for i := 0; i < b.N; i++ { tp := ParseTypeNoAlloc(testPackages[i % 3]) runtime.KeepAlive(tp) BenchmarkParseNoAlloc 8.699 ns/op 0 B/op 0 allocs/op
  • 19. Оптимизация. Примеры. Строки func ExternalLibFunc(typ string) { } func BenchmarkExternal(b *testing.B) { var str string for i := 0; i < b.N; i++ { str = string(testPackages[i % 3].typ) ExternalLibFunc(str) } } BenchmarkExternal 14.74 ns/op 5 B/op 1 allocs/op func (p *RawPackage) TypeUnsafe() string { return *(*string)(unsafe.Pointer(&p.typ)) } func BenchmarkExternalNoAlloc(b *testing.B) { var str string for i := 0; i < b.N; i++ { str = testPackages[i % 3].TypeUnsafe() ExternalLibFunc(str) } } BenchmarkExternalNoAlloc 1.366 ns/op 0 B/op 0 allocs/op
  • 20. Оптимизация. Примеры. Контейнеры func ManualBenchmark(f func(), benchName string) { iterCnt := 10_000 startMs := &runtime.MemStats{} runtime.ReadMemStats(startMs) startTime := time.Now().UnixNano() for i := 0; i < iterCnt; i++ { f() } endTime := time.Now().UnixNano() endMs := &runtime.MemStats{} runtime.ReadMemStats(endMs) fmt.Printf( "%s %d ns/op %d b/op %d allocs/op n", benchName, (endTime-startTime)/int64(iterCnt), (endMs.HeapAlloc- startMs.HeapAlloc)/uint64(iterCnt), (endMs.Mallocs- startMs.Mallocs)/uint64(iterCnt), ) }
  • 21. Оптимизация. Примеры. Контейнеры type Storage struct { data []interface{} } func (s *Storage) Add(el int) { s.data = append(s.data, el) } var nums = []int{3, 2, 20, 5} ManualBenchmark(func() { intStorage := &Storage{} for _, v := range nums { intStorage.Add(v) } }, "DefaultStorageBenchmark") DefaultStorageBenchmark 208 ns/op 112 b/op 3 allocs/op type IntStorage struct { data []int } func (s *IntStorage) Add(el int) { s.data = append(s.data, el) } ManualBenchmark(func() { intStorage := &IntStorage{} for _, v := range nums { intStorage.Add(v) } }, "IntStorageBenchmark") IntStorageBenchmark 104 ns/op 56 b/op 3 allocs/op
  • 22. Оптимизация. Примеры. Контейнеры int = int64 (для 64битой машины) SizeOf(int) = 64 (bit) = 8 (byte) interface{} type emptyInterface struct { typ *rtype word unsafe.Pointer } SizeOf(interface{}) = 128 (bit) = 16 (byte) go run -gcflags=-G=3 main.go
  • 23. Оптимизация. Примеры. Контейнеры type genericStorage[T comparable] struct { data []T } func (s *genericStorage[T]) Add(el T) { s.data = append(s.data, el) } ManualBenchmark(func() { intStorage := &genericStorage[int]{} for _, v := range nums { intStorage.Add(v) } }, "GenericStorageBenchmark") DefaultStorageBenchmark 208 ns/op 112 b/op 3 allocs/op IntStorageBenchmark 104 ns/op 56 b/op 3 allocs/op GenericStorageBenchmark 103 ns/op 56 b/op 3 allocs/op
  • 24. Оптимизация. Бонус А что если Cgo? Как быть с утечками? Ответ: еще одна тулза - Valgrind!