Как я могу оценить использование памяти std::map?

Например, у меня есть std::map с известными sizeof(A) и sizeof(B), а внутри map есть N записей. Как бы вы оценили его использование памяти? я бы сказал, что это что-то вроде

(sizeof(A) + sizeof(B)) * N * factor

Но что является фактором? Может другая формула?

Может быть, проще попросить верхнюю границу?


person Drakosha    schedule 06.04.2009    source источник
comment
Чтобы было ясно, это std::map<A, B>, верно?   -  person the swine    schedule 21.09.2014


Ответы (7)


Оценка будет ближе к

(sizeof(A) + sizeof(B) + ELEMENT_OVERHEAD) * N + CONTAINER_OVERHEAD

Для каждого добавляемого элемента существуют дополнительные затраты, а также фиксированные затраты на поддержание структуры данных, используемой для структуры данных, хранящей карту. Обычно это бинарное дерево, такое как красно-черное дерево. Например, в реализации GCC C++ STL ELEMENT_OVERHEAD будет sizeof(_Rb_tree_node_base), а CONTAINER_OVERHEAD будет sizeof(_Rb_tree). К приведенному выше рисунку следует также добавить накладные расходы на структуры управления памятью, используемые для хранения элементов карты.

Вероятно, проще получить оценку, измерив потребление памяти вашим кодом для различных больших коллекций.

person Diomidis Spinellis    schedule 06.04.2009
comment
Хотя я полностью с вами согласен, я хотел бы иметь некоторую верхнюю границу, не зная внутренних размеров структуры STL. - person Drakosha; 06.04.2009
comment
Не будет ли N узлов дерева? - person Martin York; 06.04.2009
comment
Я не согласен с этой оценкой, обычно листовые узлы имеют тот же размер, что и нелистовые узлы, поэтому часть «+ TREE_NODE_SIZE * log2(N)» неверна. - person Don Neufeld; 06.04.2009
comment
Для MSVC (VS2010) я нашел соответствующую конструкцию узла в файле xtree::class _Tree_nod‹Traits›::struct _Node. Узел содержит 3 _NodePtrs (left, right, parent -> 12/24 байта в 32/64-битных системах) плюс 2 символа (_Color и _Isnil) в дополнение к value_type (который является std::pair‹key, value›) . Это оставляет мне служебные данные элемента 14/26 байтов на запись карты. - person Daniel; 31.08.2018
comment
@Diomidis, есть ли возможность получить размер (_Rb_tree)? Я получаю ошибку отсутствующих аргументов шаблона... спасибо - person Taw; 25.11.2018
comment
@Taw: имена структур зависят от реализации. Загляните внутрь файла заголовка, чтобы увидеть фактическое имя и тип. В вашем случае кажется, что вам также нужно указать тип элемента в качестве аргумента. - person Diomidis Spinellis; 26.11.2018
comment
Спасибо за пояснения, но у меня проблемы с получением символов _Rb_tree_node_base и _Rb_tree, компилятор говорит, что они не объявлены. Я включил ‹map›, я также включил stl_tree.h (полный путь), и все равно это не работает... - person Taw; 27.11.2018
comment
Ваш компилятор может использовать другую реализацию с другими символами. Чтобы найти их, вам нужно изучить заголовочный файл и файлы заголовков, которые он может включать. - person Diomidis Spinellis; 28.11.2018

Вы можете использовать MemTrack, созданный Кертисом Бартли. Это распределитель памяти, который заменяет используемый по умолчанию и может отслеживать использование памяти вплоть до типа выделения.

Пример вывода:

-----------------------
Memory Usage Statistics
-----------------------

allocated type                        blocks          bytes  
--------------                        ------          -----  
struct FHRDocPath::IndexedRec          11031  13.7% 2756600  45.8%
class FHRDocPath                       10734  13.3%  772848  12.8%
class FHRDocElemPropLst                13132  16.3%  420224   7.0%
struct FHRDocVDict::IndexedRec          3595   4.5%  370336   6.2%
struct FHRDocMDict::IndexedRec         13368  16.6%  208200   3.5%
class FHRDocObject *                      36   0.0%  172836   2.9%
struct FHRDocData::IndexedRec            890   1.1%  159880   2.7%
struct FHRDocLineTable::IndexedRec       408   0.5%  152824   2.5%
struct FHRDocMList::IndexedRec          2656   3.3%  119168   2.0%
class FHRDocMList                       1964   2.4%   62848   1.0%
class FHRDocVMpObj                      2096   2.6%   58688   1.0%
class FHRDocProcessColor                1259   1.6%   50360   0.8%
struct FHRDocTextBlok::IndexedRec        680   0.8%   48756   0.8%
class FHRDocUString                     1800   2.2%   43200   0.7%
class FHRDocGroup                        684   0.8%   41040   0.7%
class FHRDocObject * (__cdecl*)(void)     36   0.0%   39928   0.7%
class FHRDocXform                        516   0.6%   35088   0.6%
class FHRDocTextColumn                   403   0.5%   33852   0.6%
class FHRDocTString                      407   0.5%   29304   0.5%
struct FHRDocUString::IndexedRec        1800   2.2%   27904   0.5%
person Xavier Nodet    schedule 06.04.2009

Если вы действительно хотите узнать объем памяти, занимаемой во время выполнения, используйте собственный распределитель и передайте его при создании карты. См. книгу Джосуттиса и эту страницу (для пользовательского распределителя) .

Может быть, проще попросить верхнюю границу?

Верхняя граница будет зависеть от точной реализации (например, от конкретного используемого варианта сбалансированного дерева). Может быть, вы можете сказать нам, почему вам нужна эта информация, чтобы мы могли помочь лучше?

person dirkgently    schedule 06.04.2009
comment
Это единственный способ получить точное число. - person David Lehavi; 06.04.2009
comment
Может ли внутренний распределитель STL предоставить информацию о том, сколько памяти полностью используется STL? - person Drakosha; 06.04.2009
comment
@Drakosha: Нет, этот распределитель не предназначен для этого. Вот почему вам нужно создать собственный, который будет сообщать все, что вы хотите. - person dirkgently; 06.04.2009
comment
У Стефана Т. Лававей также есть хорошая статья о пользовательских распределителях: blogs.msdn.com/vcblog/archive/2008/08/28/the-mallocator.aspx Прочтите комментарии, чтобы узнать немного об использовании ‹cheader› и ‹header.h›. Теперь я могу чувствовать себя вправе продолжать использовать вариант .h заголовков C в моем коде C++! - person Michael Burr; 06.04.2009
comment
@Michael: Почему вдруг заголовки? Некоторый контекст будет полезен! - person dirkgently; 06.04.2009

Недавно мне нужно было ответить на этот вопрос для себя, и я просто написал небольшую тестовую программу, используя std::map, которую я скомпилировал под MSVC 2012 в 64-битном режиме.

Карта со 150 миллионами узлов поглощает ~ 15 ГБ, что подразумевает 8 байтов L, 8 байтов R, 8 байтов ключа int и 8 байт данных, всего 32 байта, поглощая около 2/3 памяти карты для внутренние узлы, оставляя 1/3 для листьев.

Лично я обнаружил, что это удивительно низкая эффективность памяти, но это то, что есть.

Надеюсь, это станет удобным эмпирическим правилом.

PS: Накладные расходы std::map - это размер одного узла AFAICT.

person user2548100    schedule 03.09.2013
comment
Если вам нужна более высокая эффективность использования памяти, вы можете использовать code.google.com/p/cpp- дерево - person Drakosha; 09.09.2013
comment
Смотрите мой комментарий в ответе Диомидиса Спинеллиса. Я обнаружил накладные расходы элементов на запись карты: 3 указателя + 2 символа -> 14/26 байтов на 32/64 бит в дополнение к паре ключ-значение. Доля накладных расходов, конечно, будет зависеть от размеров ваших ключей и значений. - person Daniel; 31.08.2018

Формула больше похожа на:

(sizeof(A) + sizeof(B) + factor) * N

где factor — накладные расходы на запись. Карты C++ обычно реализуются как красно-черные деревья. Это бинарные деревья, поэтому будет как минимум два указателя на левый/правый узлы. Также будут некоторые вещи для реализации - возможно, родительский указатель и "цветовой" индикатор, поэтому фактор может быть чем-то вроде

(sizeof( RBNode *) * 3 + 1) / 2

Однако все это сильно зависит от реализации — чтобы убедиться в этом, вам действительно нужно изучить код реализации вашей собственной библиотеки.

person Community    schedule 06.04.2009

Я также искал что-то, чтобы рассчитать размер std::map. Я попробовал то, что было объяснено в ответе Diomidis Spinellis, и расширил его ответ здесь, что может быть полезно для других.

Я расширяю его ответ, добавляя несколько строк кода.

#include <bits/stl_tree.h>
int main(int argc, char *argv[])
{
    std::cout << sizeof(std::_Rb_tree_node_base) << std::endl;
    return 0;
}

Выходные данные (на моем процессоре ARM Cortex A-9 iMX6Solo-X под управлением Linux [4.9.175] и компилятора: arm-fslc-linux-gnueabi-gcc (GCC) 7.3.0):

16

Учитывая std::map<A, B>, меня интересует размер ELEMENT_OVERHEAD, так как он линейно растет с количеством элементов, присутствующих на карте. Было обнаружено, что ELEMENT_OVERHEAD эквивалентен sizeof(std::_Rb_tree_node_base), поэтому для моей системы имеет значение 16.

(sizeof(A) + sizeof(B) + ELEMENT_OVERHEAD) * N + CONTAINER_OVERHEAD
person abhiarora    schedule 31.03.2020

Размер карты действительно зависит от реализации карты. У вас могут быть разные размеры на разных компиляторах/платформах, в зависимости от того, какую реализацию STL они предоставляют.

Зачем вам этот размер?

person Cătălin Pitiș    schedule 06.04.2009
comment
Хорошо, г++. Мне нужен этот размер, чтобы знать, сколько записей я могу хранить в памяти, прежде чем начать обмен. Мне нужна верхняя граница. - person Drakosha; 06.04.2009
comment
Если вам нужна верхняя граница, я предлагаю взглянуть на реализацию карты, чтобы увидеть, как реализован объект узла карты, и рассмотреть размер членов узла карты как дополнительный к размеру ключа и элемент. Имейте в виду, что этот подход зависит от платформы и компилятора. - person Cătălin Pitiș; 06.04.2009
comment
Отключите виртуальную систему и напишите тест для медленного увеличения размера тестовой карты. Достаточно скоро вы узнаете, наблюдая за метрикой Пикового рабочего набора Windows Task Manager, когда вам не хватает памяти. Я предполагаю, что некоторые люди предпочли бы обсудить что-то до смерти, вместо того, чтобы разрабатывать простой тест и знать наверняка. Эти люди ничего не добавляют к миру и поглощают много времени и умственных усилий, потому что они не могут остановиться, чтобы подумать о том, как построить хороший тест рассматриваемых переменных. Арррггх - person ; 09.09.2013