2015-08-06 4 views
3

Я хочу ограничить максимальную карту X байтами. По-видимому, нет простого способа вычислить длину байта карты.Golang: вычисление длины памяти (или длины байта) карты

"encoding/binary" пакет имеет хорошую функцию Size, но он работает только для фрагментов или «фиксированных значений», а не для карты.

Я мог бы попытаться получить все пары ключ/значение с карты, вывести их тип (если это map[string]interface{}) и вычислить длину - но это было бы громоздким и, вероятно, неправильным (потому что это исключало бы "внутреннюю" golang стоимость самой карты - управление указателями на элементы и т. д.).

Любой предложенный способ сделать это? предпочтительно пример кода.

+0

Вы не можете делать то, что хотите, надежным способом: например. «внутренние расходы golang» зависят от размера слова вашего устройства. Я, хотя думаю, что понятие «карта использует X байтов» является ошибочным; рассмотрите карту, содержащую срез: подсчитаете ли вы байты массива поддержки на карте? Я бы рекомендовал искать другое решение, тем более, что использование 'interface {}' имеет уродливый запах. – Volker

+0

Спасибо за комментарий. Практический пример довольно простой: я хочу наложить ограничение размера на кеш (вместо ограничения по времени). Если я хочу сделать это с помощью карты - возможно, наиболее подходящего примитива, который будет использоваться в качестве объекта кеша в Go - (давайте даже предположим, что это не карта строки/интерфейса), каковы мои варианты в языке (с использованием внешнего инструмент для этого кажется излишним)? – orcaman

+1

Ограничение объема данных в кеше является допустимым прецедентом, но это разумно, если вы храните значительное количество данных с переменным размером в кеше, что означает, что накладные расходы самой карты будут незначительными. Если у вас есть данные фиксированного размера, вы можете ограничить len карты. – Volker

ответ

7

Это the definition для заголовка карты:

// A header for a Go map. 
type hmap struct { 
    // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and 
    // ../reflect/type.go. Don't change this structure without also changing that code! 
    count int // # live cells == size of map. Must be first (used by len() builtin) 
    flags uint32 
    hash0 uint32 // hash seed 
    B  uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items) 

    buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. 
    oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing 
    nevacuate uintptr  // progress counter for evacuation (buckets less than this have been evacuated) 
} 

Расчет его размер довольно проста (unsafe.Sizeof).

Это определение для каждого отдельного ковша на карте указывает на:

// A bucket for a Go map. 
type bmap struct { 
    tophash [bucketCnt]uint8 
    // Followed by bucketCnt keys and then bucketCnt values. 
    // NOTE: packing all the keys together and then all the values together makes the 
    // code a bit more complicated than alternating key/value/key/value/... but it allows 
    // us to eliminate padding which would be needed for, e.g., map[int64]int8. 
    // Followed by an overflow pointer. 
} 

bucketCnt константа определяется как:

bucketCnt  = 1 << bucketCntBits // equals decimal 8 
bucketCntBits = 3 

Окончательный расчет будет:

unsafe.Sizeof(hmap) + (len(theMap) * 8) + (len(theMap) * 8 * unsafe.Sizeof(x)) + (len(theMap) * 8 * unsafe.Sizeof(y)) 

Где theMap - ваше значение для вашей карты, x - это значение типа ключа карты и y значение типа значения карты.

Вам придется разделить структуру hmap с вашим пакетом через сборку, аналогично thunk.s во время выполнения.

+0

JFYI 'thunk.s' заменен директивой компилятора [' // go: linkname'] (https://golang.org/cmd/compile/#hdr-Compiler_Directives). – tsuna

+0

Можете ли вы обновить этот ответ? Очевидно, что ничто из этого не работает. Структура hmap совершенно другая, ваш ответ не влияет на емкость, и вы не можете делиться структурами через сборку (и не можете ли вы с помощью go: linkname) – Smaug

+0

Smaug: Привет, правда в том, что реализация карты будет изменяться снова и снова в будущем. Поэтому я оставляю ответ как руководство, а не решение. Вы можете использовать сборку для обмена именами. – thwd

Смежные вопросы