Как это возможно, что эти два фрагмента кода имеют одинаковое использование памяти?

Первый случай:

#include <vector>

int main() {
    const int iterations = 1'000'000;
    std::vector<const char *> c;
    for (int i = 0; i < iterations; i++) {
        c.push_back("qwertyuiopqwertyuiopqwertyuiopqwertyuiopqwertyuiop");
    }
}

Второй случай:

#include <vector>

int main() {
    const int iterations = 1'000'000;
    std::vector<const char *> c;
    for (int i = 0; i < iterations; i++) {
        c.push_back("qwerty");
    }
}

В обоих случаях отображаемое использование памяти активным процессом составляет около 11 МБ.

Первая мысль заключалась в том, что использование памяти относится только к размеру указателей, но тогда как я могу узнать извне, сколько памяти использует определенное программное обеспечение? (Без явного вычисления размера внутри кода)

Редактировать: Я думал, что с c.push_back("qwerty") я каждый раз создаю новую строку. Это было моей целью. Мне удалось сделать это сейчас, изменив код таким образом:

#include <vector>

int main() {
    const int iterations = 1'000'000;
    std::vector<const char *> c;
        for (int i = 0; i < iterations; i++) {
            std::string* s = new std::string("sadadasd");
            c.push_back((*s).c_str());
    }
}

Это выглядит ужасно, но, по крайней мере, теперь использование памяти имеет смысл. Есть ли более элегантный способ добиться этого? (Я имею в виду без введения std::string и использования только const char*)

Да, обе программы создают std::vector с миллионом копий одного и того же значения указателя.

Botje 25.11.2022 15:48

Пространство, занимаемое с точки зрения операционной системы, вероятно, будет отличаться от того, что фактически занято в локальном пространстве вашего процесса.

πάντα ῥεῖ 25.11.2022 15:52

@OP Почему вы считаете, что результаты должны быть другими? Ваш код ничем не отличается от того, если бы у вас было std::vector<int>, в первой программе вы заполнили вектор миллионом 0, а во второй программе вы заполнили вектор миллионом 1000000. Просто потому, что число, которое вы используете для заполнения вектора, больше, это не означает, что использование памяти увеличивается. Оба вектора по-прежнему являются векторами int, точно так же, как оба ваших вектора являются const char *.

PaulMcKenzie 25.11.2022 15:57

Выглядит правильно. Около 8 МБ (вероятно, ровно 8 МБ, если используются большие страницы) указателей, 1 МБ стека, 2+ МБ в основном пустого пространства, содержащего начальные динамические выделения, диспетчер памяти и т. д. и образ вашей программы.

Revolver_Ocelot 25.11.2022 16:06

Я добавил детали в основной вопрос.

Ceccoclat 25.11.2022 16:16

Нет, если вы хотите иметь возможность хранить уникальные строки, вам нужно будет выделить память для всех из них. Если вы не хотите хранить дубликаты, вам нужна другая структура данных.

Pepijn Kramer 25.11.2022 16:24

Да, целью было иметь 1 миллион идентичных, но уникальных строк.

Ceccoclat 25.11.2022 16:32

Прямо сейчас ваш код написан так, чтобы гарантировать, что вы столкнетесь с миллионом утечек памяти, потому что каждая из этих std::string*s, которые вы new, немедленно потеряны, чтобы никогда не быть deleted. Трудно ответить, есть ли «более элегантный способ добиться этого», когда мы понятия не имеем, что такое «это». «Создайте вектор const char*, который указывает на разные, но идентичные строки, нет, я не могу просто создать вектор std::strings», по меньшей мере, своеобразно.

Nathan Pierson 25.11.2022 16:41

Есть ли более элегантный способ добиться чего?

user253751 25.11.2022 16:42

«Есть ли более элегантный способ добиться этого?» - это другой вопрос, чем тот, который был задан изначально, поэтому он не по теме этого вопроса. Я предлагаю переместить его в новый пост, прежде чем кто-то решит использовать это как предлог, чтобы закрыть этот вопрос, поскольку «требует большего внимания - задает несколько вопросов одновременно». (Новый пост также должен лучше описывать ваши требования, например, объяснять, почему std::vector приемлемо, а std::string — нет.)

JaMiT 25.11.2022 16:55

«Это» означает «Да, целью было иметь 1 миллион идентичных, но уникальных строк». написано чуть выше вашего комментария. Но это также написано в редактировании, когда я сказал, что думал, что «я думал, что с c.push_back («qwerty») я каждый раз создавал новую строку. Это было моей целью». Кроме того, я скопировал некоторый код, чтобы показать вам, чего мне нужно достичь.

Ceccoclat 25.11.2022 17:03

За то, что я изменил вопрос, да, вы правы. Мне жаль

Ceccoclat 25.11.2022 17:06

Я думал, что с c.push_back("qwerty") я каждый раз создавал новую строку. Если бы вы использовали vector<string>, то это было бы так.

Eljay 25.11.2022 18:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
13
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Указатель занимает (обычно) 8 байт.

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

Обе программы включают только одну копию строки. Дополнительные 44 байта — капля в море. Вторая программа могла бы даже не использовать дополнительные 44 байта, если бы они все равно были неиспользованными байтами заполнения, что вполне вероятно, поскольку ОС может распределять память только в 4096-байтовых фрагментах, называемых страницами.

Я добавил детали в основной вопрос.

Ceccoclat 25.11.2022 16:18

Другие вопросы по теме