растёт не линейно? Я понимаю что память кусками выделяется но при добавлении нескольких элементов память растёт сотнями байт а при добавлении миллион и миллион+1 элемент уже изменени на десятки килобайт
вот код
func BenchmarkMapUint8(b *testing.B) {
for n := 0; n < b.N; n++ {
caseMapUint8 = make(map[int]uint8)
for i := 0; i < length; i++ {
caseMapUint8[i] = 1
}
}
}
1 элемент
BenchmarkMapUint8-4 8657696 133.5 ns/op 144 B/op 2 allocs/op
8 элементов
BenchmarkMapUint8-4 8657696 133.5 ns/op 144 B/op 2 allocs/op
9 элементов уже берётся новый кусок памяти
BenchmarkMapUint8-4 1431505 833.0 ns/op 320 B/op 3 allocs/op
По идее один элемент должен быть где то (144-48)/8 приблизительно 16 байт
но если делать 1000000
То
BenchmarkMapUint8-4 1 2059244014 ns/op 444518240 B/op 306589 allocs/op
Явно тут не 16 байт на элемент
А если 1000001 то один элемент добавил 24 килобайта
BenchmarkMapUint8-4 1 2049380999 ns/op 444542136 B/op 306835 allocs/op
Вынесите мап в глобальную переменную, иначе компилятор сможет тут всё оптимизировать в ноль
Сама переменная и так глобальная
А, ок, не заметил
У меня прямо встречный вопрос в стиле @onokonem : «А Вы знаете, как работает map'а под капотом?»
Приблизительно. По этому и спрашиваю. У Мапа память растёт нелинейно? Или это из за того что GC не успевает?
Что должен успевать или не успевать gc?
Вы можете его отключить и проверить. На первый взгляд, оно тут не при чём
Он не успевает память очистить. Это предположение. Что тест заканчивается быстрее чем жс успевает почистить память.
От чего почистить?
он ее довольно быстро чистит. но можно глянуть в профайлере, конечно
Но меня больше интересует вопрос, а с чего предположение, что мапа в принципе может расти линейно? Ну т.е. что в принципе могло привести к такому выводу?
Я предположил что при добавлении элемента в мап он может для служебных целей выделять память. Например при расчёте хэша. А потом освобождать
это все произойдет на стеке
а почему должно быть не линейно? Размер элемента фиксирован. Хэш насколько я понимаю тоже. Откуда нелинейность должна взяться?
Тесть это нормально для мапа что на миллионном элементе кажды новый элемент занимает 24 Кбайта?
Я и так это уже сказал. Если не хотите отвечать то просто не отвечайте.
Я, кстати, с трудом могу понять, почему до 8 всё было ok. Точнее, я не понимаю откуда там 2 аллокации
Я намекаю на то, что придётся посмотреть какой-нибудь 10-минутный ролики или текст - как устроена мапа
Вот например: https://habr.com/ru/post/457728/ можно начать со слов "Мапа в Go — это..."
А 1000002 тоже 24 отожрет?
А зачем линейно? Аллокация памяти - штука дорогая.
Да причем тут аллокация
Раз речь про профайлер зашла, норм в проде профайлером снимать нагрузки? Или в проде лучше его не использовать?
Забавно, кстати, @onokonem , это он при grow что-то явно почистить не успевает действительно. Хотя бенч flat или cum показывает? Если cum, то я не понимаю
А всё, я понял почему
По вашей ссылке написано В исходном коде можно найти строчку: // Maximum average load of a bucket that triggers growth is 6.5. то есть, если в каждом «ведре» в среднем более 6,5 элементов, происходит увеличение массива buckets. При этом выделяется массив в 2 раза больше, а старые данные копируются в него маленькими порциями Это же память не в стеке выделяется? Если при новом добавлении элемента мап выделяем память и потом освобождает, то бенчмарк насколько я понимаю не покажет освобождение.
в стеке тольео то, размер чего можно при компиляции вычислить, по очевидным причинам
Просто выше сказали что мап в стеке только выделяет память.
Обсуждают сегодня