Распределение памяти C ++ - PullRequest
4 голосов
/ 05 апреля 2011

В основном это вопросы проектирования компилятора. Когда ваш компилятор компилирует это, например:

int * pData = new int[256];

Как распределяется память на лету? Компилятор выполняет вызов подпрограммы ОС, которая выделяет вам память, или компилируется функция, которая выделяет вам память?

Кроме того, когда вы пишете что-то вроде этого:

if (x == 5)
    int y;

Поскольку память не выделяется во время выполнения, я предполагаю, что данные занимают некоторое место в сегменте данных программы. Поскольку компилятор не может реально определить, будет ли выполняться ветвь int y; во время выполнения, зарезервирована ли память для переменной независимо от того, выполняется int y; или нет? И если он зарезервирован независимо, не является ли более эффективным использование памяти для распределения переменных в блоке, которые могут выполняться или не выполняться?

o.o спасибо

Ответы [ 7 ]

6 голосов
/ 05 апреля 2011

По первому вопросу: Когда компилятор встречает оператор new, как в вашем примере:

int * pData = new int[256];

Он эффективно генерирует код, который выглядит следующим образом:

int *pData = reinterpret_cast<int*>(::operator new(256 * sizeof(int)));
// the compiler may also choose to reserve extra space here or elsewhere to
// "remember" how many elements were allocated by this new[] so delete[] 
// can properly call all the destructors too!

Если должен быть вызван конструктор, он также генерируется (в этом примере, я считаю, ни один конструктор не вызывается).

operator new(std::size_t) - это функция, которая реализуется стандартной библиотекой, часто, , но не всегда , она сводится к вызову malloc.

malloc потребуется совершить системный вызов , чтобы запросить память у ОС. Поскольку распределители ОС обычно работают с большими блоками памяти фиксированного размера, malloc не будет делать этот вызов каждый раз, только когда он исчерпал память, которую он имеет в настоящее время.


По второму вопросу : Для локальных переменных это действительно зависит от компилятора. Стандарт не упоминает о стеке. Однако, скорее всего, вы работаете на общей архитектуре, работающей на общей ОС и использующей общий компилятор: -).

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

Затем (в c ++), когда переменная встретится, она вызовет конструктор. Теоретически, он может корректировать стек по мере необходимости, но это будет сложно доказать, что он правильный и менее эффективный. Обычно резервирование стекового пространства - это отдельная инструкция, поэтому выполнение всего этого за один раз довольно оптимально.

2 голосов
/ 05 апреля 2011

Как распределяется память на лету?Компилятор выполняет вызов подпрограммы ОС, которая выделяет вам память, или это компилируемая функция, которая выделяет память для вас?

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

- память, зарезервированная для переменной, независимо от того, "int y;"выполняется?И если он зарезервирован независимо, не является ли он более эффективным с точки зрения памяти для выделения переменных, находящихся в блоке, которые могут или не могут быть выполнены?

Обычно нет - место для y будет выделен, только если соответствующий код был выполнен.Переменные с автоматическим классом хранения обычно находятся в стеке, поэтому освободить место для них так же просто, как изменить указатель стека.Тем не менее, в этом случае компилятор может делать практически все, что хочет, поэтому проверка выходных данных из вашей цепочки инструментов - единственный способ узнать наверняка.

1 голос
/ 05 апреля 2011

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

1 голос
/ 05 апреля 2011

Локальные переменные (int y) размещаются в стеке.

То же самое относится и к указателю, однако выражение «new» -ed выделяется в куче, обычно через своего рода вызов malloc. Точный метод и компоновка кучи определяются реализацией.

В сегменте данных находятся только глобальные статические данные.

Пример int y будет оптимизирован, поскольку он не используется.

В отличие от, например, C #, C ++ не позволили уменьшить область видимости для переменной, поэтому обернуть недолговечный локальный объект в {SomeClass y; } может помочь, поэтому он разрушается раньше

Тем не менее, я почти уверен, что для простых типов (таких как int) такого ограничения не существует, потому что для них не может быть деструктора

0 голосов
/ 05 апреля 2011

Для первого вопроса:

Компилятор генерирует код для вызова функции operator new, которая сама обычно вызывает malloc из библиотеки времени выполнения C, которая сама выполняет вызовв некоторую специфичную для ОС библиотеку, которая (вы можете видеть, куда это идет) в какой-то момент завершается переключением в режим ядра и выделением памяти для процесса.

В любом случае нативный код, который генерирует компилятор дляВаша собственная программа не выполняет само выделение.

По второму вопросу:

Память для int y выделена в стеке.Независимо от того, выполняется ли условие, в простейшем неоптимизирующем случае выделение стекового пространства будет происходить каждый раз, когда элемент управления входит в вашу функцию.

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

0 голосов
/ 05 апреля 2011

Случай 1: он вызовет подпрограмму ОС для выделения памяти в куче.Операционная система управляет памятью.

Случай 2: это выделяется в стеке.Стек предварительно выделен вашему процессу и используется для аргументов локальных переменных и функций.

0 голосов
/ 05 апреля 2011

Это действительно зависит от компилятора для 2-го примера, поэтому у нас есть ключевое слово volatile (в случае, если мы сопоставляем переменные с адресами, которые меняются), или оно может просто дать вам предупреждение, но я уверен, что оно будет его включать. в вашу программу (иногда вы хотите увеличить размер стека вашего метода по хакерским причинам). Первый пример по сути вызывает malloc (256 * sizeof (int)) и возвращает указатель на этот сегмент.

...