Вычислить выделенную память для std :: string (и использовать строки в std :: vector) - PullRequest
0 голосов
/ 17 января 2019

Я хочу вычислить, сколько памяти выделяется при создании и назначении значений для строки.

string s = "";
cout << sizeof(s) << endl;
cout << sizeof(s.at(0)) * s.capacity() << endl;
s = "1234567890qwertz";
cout << sizeof(s) << endl;
cout << sizeof(s.at(0)) * s.capacity() << endl;

Это вся память, которую использует моя строка? Начальная / статическая часть, которую я получаю, просто вызывая sizeof (s) (будучи на моей машине 40 байт) плюс динамическая часть - размер одного символа, умноженный на заполненные заполнители для эффективного изменения размера строк (on На моей машине строка s сначала выделяла блок из 15 байт до точки, где текст слишком длинный, поэтому после второго назначения динамическая часть составляет 31 байт). Почему не 16 а 32 байта кстати?

Правильно ли думать об этом (статический + динамический для каждой строки - вся занимаемая память)?

Это означает, что если у меня есть std :: vector строк, и я хотел бы также рассчитать всю память для этого вектора, мне нужно было бы сделать то же самое: я добавляю исходный / статический размер моего вектор, чтобы получить плюс динамическая часть, что означает общий объем памяти, занимаемый одной строкой, как я делаю это выше для каждой строки внутри вектора?

vector<string> cache;
// fill cache with strings of dynamic length
int size = sizeof(cache);
for (int i = 0; i < cache.size(); i++)
{
    size += sizeof(cache[i]);
    size += sizeof(cache[i].at(0)) * cache[i].capacity();
}

Итак, чтобы подвести итог, правильный ли это объем памяти, занятый моим "кэшем"?

Edit: Или мне также нужно принять во внимание, что сам std :: vector также имеет .capacity ()> = .size (), что может означать, что мне действительно нужно сделать это:

для каждого cache.capacity() - мне нужно было бы добавить sizeof(cache[i]) и дополнительно за каждый cache.size() - добавить sizeof(cache[i].at(0)) * cache[i].capacity() ??

Ответы [ 3 ]

0 голосов
/ 17 января 2019

Существует простая причина, почему емкость строки на единицу меньше, чем вы ожидаете, и это

s.c_str()

Строка C ++ хранится в блоке памяти с объемом, определяющим общий размер и размер используемого пространства. Но строка C завершается 0. Строка C ++ резервирует один дополнительный байт в конце блока памяти для хранения 0. Таким образом, s.c_str() всегда завершается 0.

Таким образом, память, используемая динамической частью строки, равна емкости + 1.

Что касается общего объема памяти, занятой строкой или вектором строк, Натан Оливер ответил, что я думаю. Но остерегайтесь векторов, содержащих одну и ту же строку несколько раз.

0 голосов
/ 17 января 2019

Если вы хотите узнать, сколько места занимает ваш std::vector<std::string>, рассчитайте его:

auto netto_memory_use(std::vector<std::string> const& x) noexcept {
    return std::accumulate(
        begin(x),
        end(x),
        sizeof x + sizeof x[0] * x.capacity(),
        [](auto n, auto&& s) {
            if (std::less<void*>()(data(s), &s)
            || std::greater_eq<void*>()(data(s) + s.capacity(), &s + 1))
                return n + s.capacity() + 1;
            return n;
        });
    }

Я использовал std::less<void*> / std::greater_eq<void*>, чтобы использовать их при определении полного порядка, в отличие от просто использования операторов сравнения.

Аккумулятор проверяет применяемую оптимизацию малых строк (SSO) перед добавлением емкости строки. Конечно, все строки с нулевой емкостью могут использовать один и тот же статически распределенный терминатор. Или емкость и / или длина могут быть выделены вместе с символьными данными.
Тем не менее, это должно быть хорошим приближением к используемой памяти, кроме издержек системы управления памятью.

0 голосов
/ 17 января 2019

На этот вопрос будет сложно ответить. Наивно вы могли бы подумать, что общий объем потребляемой памяти будет

vector_capacity * sizeof(std::string) + sum_of_capacity_of_each_string_in_the_vector

Но это скорее верхний предел, а не то, что можно было бы фактически потреблять. Например, оптимизация короткой строки позволяет std::string хранить строковые данные в хранилище, которое потребляет сам строковый объект (то, что вы называете статическим размером). Если это так, то фактическое использованное пространство будет

vector_capacity * sizeof(std::string)

, а емкость каждой строки в векторе будет зависеть от того, сколько места вы занимаете без выделения дополнительного пространства. Вам нужно будет проверить свою реализацию, чтобы увидеть, использует ли она SSO и длинную строку, которую он будет хранить в строковом объекте, чтобы узнать, использует ли значение емкости внутреннее пространство строк или фактически использует дополнительную память. Это делает фактическое потребляемое пространство

vector_capacity * sizeof(std::string) + sum_of_capacity_of_each_string_in_the_vector_where_
                                        the_capcity_is_more_than_the_sso_amount

В тебе расчет sizeof(cache[i].at(0)) не нужен. std::string использование char и sizeof(char) гарантированно будет 1

...