Продолжение предыдущего поста (ссылка) 👍👍
На самом деле, уже есть предложения по исправлению, например, поменять местами поля в структуре. Это действительно сработает, ведь компилятор не будет добавлять один байт паддинга для пустой структуры. Можно проверить это решение бенчмарками (размер слота, в котором хранятся ключи и значения, указан последним):
type group struct {
ctrl uint64
slots [abi.SwissMapGroupSlots]struct {
key keyType
elem elemType
}
}
Изначальное расположение полей:
map[addrDetail]struct {}: key=24 elem=0 slot=32
map[any]struct {}: key=16 elem=0 slot=24
map[canceler]struct {}: key=16 elem=0 slot=24
map[*conn]struct {}: key=8 elem=0 slot=16
map[GoID]struct {}: key=8 elem=0 slot=16
map[*http2serverConn]struct {}: key=8 elem=0 slot=16
map[*net.Listener]struct {}: key=8 elem=0 slot=16
map[ProcID]struct {}: key=8 elem=0 slot=16
map[string]struct {}: key=16 elem=0 slot=24
map[_typePair]struct {}: key=16 elem=0 slot=24
map[uintptr]struct {}: key=8 elem=0 slot=16
Измененное расположение полей:
map[addrDetail]struct {}: key=24 elem=0 slot=24
map[any]struct {}: key=16 elem=0 slot=16
map[canceler]struct {}: key=16 elem=0 slot=16
map[*conn]struct {}: key=8 elem=0 slot=8
map[GoID]struct {}: key=8 elem=0 slot=8
map[*http2serverConn]struct {}: key=8 elem=0 slot=8
map[*net.Listener]struct {}: key=8 elem=0 slot=8
map[ProcID]struct {}: key=8 elem=0 slot=8
map[string]struct {}: key=16 elem=0 slot=16
map[_typePair]struct {}: key=16 elem=0 slot=16
map[uintptr]struct {}: key=8 elem=0 slot=8
Размер слотов уменьшился
Проблема такого решения состоит в том, что остальная реализация мапы сильно завязана на текущем порядке полей. Во многих методах подразумевается, что в слоте ключ идет первее элемента:
// key returns a pointer to the key at index i.
func (g *groupReference) key(typ *abi.MapType, i uintptr) unsafe.Pointer {
offset := groupSlotsOffset + i*typ.SlotSize
return unsafe.Pointer(uintptr(g.data) + offset)
}
// elem returns a pointer to the element at index i.
func (g *groupReference) elem(typ *abi.MapType, i uintptr) unsafe.Pointer {
offset := groupSlotsOffset + i*typ.SlotSize + typ.ElemOff
return unsafe.Pointer(uintptr(g.data) + offset)
}
Полностью решить эту проблему разработчики обещают в Go 1.27.
UPD: Буквально сегодня замёржили фикс в master, полностью допилив решение
😎😎 А пока, если вас спросят на собеседовании, то знайте, что в Go 1.24+
map[K]struct{} больше не гарантирует экономию памяти относительно map[K]bool (для некоторых типов ключей размер slots оказывается таким же)Ну а для тех, кто хочет комплексно изучить внутреннее устройство всех основных структур данных в Go, напоминаю, что в конце апреля стартует уникальный поток The Nature of Go.
👉👉 Link
👉👉 Link