Адрес стека разделен адресами кучи? - PullRequest
3 голосов
/ 18 июня 2010

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

Если я создал ...

pointerType* pointer = new pointerType  //creates memory address 0xffffff

А затем создал локальную переменнуюстек

localObject object

будет иметь адрес localObjects равным 0xfffffe

Или порядок кучи и стека будет совершенно другим.

Ответы [ 9 ]

3 голосов
/ 18 июня 2010

Как правило, вы обнаружите, что стек растет вниз от некоторого начального адреса, а куча растет вверх от некоторого совершенно другого начального адреса.

Как работает стек и куча (это называется динамическим хранилищем в C ++стандарт) работает точно, хотя реализация определяется и не регулируется стандартом C ++.

3 голосов
/ 18 июня 2010

Стек и куча обычно находятся в двух очень разных местах в памяти.

2 голосов
/ 18 июня 2010

адреса в памяти начинаются с наивысшего к низшему

Адреса домов на вашей улице упорядочены по возрастанию или убыванию? Ну, это зависит от того, как ты ездишь.

Так же, как почтовые адреса, адреса памяти на самом деле не упорядочены вообще. Каждый адрес просто идентифицирует уникальное место в памяти (по крайней мере, концептуально. Мы на мгновение проигнорируем сегментированную или виртуальную память).

Но когда ваш почтальон доставляет ежедневную почту, он, скорее всего, работает либо в порядке убывания, либо в порядке убывания (вероятно, как по одной стороне улицы, так и по другую сторону). Это, конечно, более эффективно, чем случайный прыжок из дома в дом. Кроме того, это значительно облегчает работу перевозчика. Если бы он прыгал от дома к дому в произвольном порядке, было бы трудно отследить, какие дома он уже посетил, а какие еще нуждаются в доставке. Если он просто идет по порядку, то положение его грузовика - это все, что ему нужно для отслеживания.

Стек похож на это. Он не занимает произвольные позиции в памяти, а вместо этого занимает первую позицию, а последующие позиции следуют в логическом порядке оттуда. Таким образом, указатель стека (часто «SP») - это все, что необходимо для отслеживания того, какие ячейки стека заняты, а какие свободны.

Куча обязательно другая, хотя. Хотя стек по своей природе имеет порядок «первым пришел - последним вышел», куча изначально неупорядочена. Память кучи может быть выделена и освобождена в любое время. Более ранние распределения могут пережить более поздние распределения. Поэтому куча должна иметь возможность выделять произвольные диапазоны адресов и должна отслеживать их все.

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

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

Большинство современных операционных систем на самом деле этого не делают. Чаще всего используется «плоское» адресное пространство, где все адреса, будь то стек, куча, код или что-то еще, относятся к одному адресному пространству. Это облегчает работу разработчика приложений, избавляя от необходимости манипулировать идентификаторами сегментов для каждого адреса.

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

Конечно, это описание является огромным упрощением, но, надеюсь, оно даст лучшее базовое понимание.

2 голосов
/ 18 июня 2010

В современных операционных системах это сложнее, чем это, но чтобы помочь вам начать:

В большинстве систем класса персональных компьютеров (*) стек и куча являются частью одного и того же адресного пространства,но по соглашению стеки обычно начинаются с высоких адресов и растут вниз по мере того, как на них проталкиваются вещи, тогда как кучи лучше всего рассматривать любую оперативную память, которая не является частью стека, пространством глобальных переменных (.data и .bss) или частьюпрограммного кода (.text), оба из которых также находятся в одном и том же адресном пространстве.

  • Это своего рода ложь, потому что процессоры x86 поддерживают сегментацию, которая сбивает с толку, но это о том, какиспользуются компьютеры, а не только те, которые они поддерживают.

Это обычно называют архитектурой фон Ньюмана - все данные и код находятся в одном адресном пространстве общего назначения.

Другая архитектураТип называется Гарвард.В Гарвардских архетектурах код живет в ПЗУ, а большинство данных - в ОЗУ, а ОЗУ и ПЗУ не разделяют адресные пространства.Это означает, что функция и переменная могут иметь один и тот же числовой адрес, но все же не находиться в одном месте.Архитектура Atmel AVR является хорошим примером этого, за исключением некоторых меньших версий, которые имеют регистры только без ОЗУ (что только запутает дело), ​​и некоторых более крупных версий, которые расширяют адресное пространство с 16 бит до 24 бит иможет (не уверен в этом) размывать границы адресных пространств.

Семейство процессоров 8051 по-прежнему отличается и более соответствует вашему вопросу.Как правило, они имеют небольшой объем оперативной памяти, которая является областью стека и находится в другом адресном пространстве, чем оперативная память общего назначения, в которой будут жить глобальные переменные и, возможно, область кучи.Они также обычно имеют свой код в другом отдельном адресном пространстве.

что такое куча

Куча - это на самом деле просто способ обработки некоторой памяти / адресного пространства, которое еще не используется.Алгоритмы, которые вы используете для выделения и освобождения памяти из этой резервной памяти, делают ее кучей .

тем, что на самом деле представляет собой стек

стековчасто немного отличаются, потому что для них часто существует аппаратная поддержка в виде инструкций для вызова, возврата, push и pop, но они даже не нужны.Аппаратная поддержка системного стека становится необходимой, когда вы начинаете работать с прерываниями, поскольку действие процессора "произошло прерывание" требует использования стека для сохранения состояния процессора перед выполнением подпрограммы обработки прерываний.

почему это часто ложь на настольных компьютерах

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

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

2 голосов
/ 18 июня 2010

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

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

1 голос
/ 18 июня 2010

pointerType* pointer = new pointerType //creates memory address 0xffffff

Вы неверно истолковали 0xffffff. Это не адрес вновь выделенной памяти - это адрес самой переменной указателя. Если вы хотите проверить, где была выделена память, вам нужно проверить значение, которое хранится в 0xffffff

0 голосов
/ 18 июня 2010

Стек и куча не являются взаимоисключающими. Представьте себе эти две гипотетические закулисные реализации компилятора:

void PreMain()
{
    char initialHeap[initialHeapSize]
    HeapPointer heapHead = &initialHeap;
    ...
    int returncode = main(argc, argv);
    ...
}

void PreMain()
{
    void * stack = GetFromOSHeap(stackSize);
    // some assembly intrinsic to replace the stack pointer
    ...
    int returncode = main(argc, argv);
    ...
}

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

0 голосов
/ 18 июня 2010

Вы всегда можете, знаете, проверить.Это одна из тех вещей, где вы можете узнать это, просто выведя значение и проверив его.Не гарантируется, что это будет одинаковым поведением на всех компьютерах или на всех компиляторах, но вы можете увидеть, в чем дело.Просто printf ("0x% x \ n", & variable), чтобы увидеть адрес переменной.Выделите несколько вещей в куче, выделите несколько вещей в стеке, затем проверьте все их адреса, и вы увидите, где они находятся, а также направление, в котором каждая из них распространяется.

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

0 голосов
/ 18 июня 2010

Как указатель, так и объект локального объекта расположены в стеке.Объект, на который указывает указатель, находится в куче.

Вот почему в C часто говорят, что есть только передача по значению.Когда вы передаете указатель на функцию, она ничем не отличается от передачи int: указатель / int на принимающий конец параметра функции - это еще одна «вещь» в стеке.Однако, поскольку значение указателя (адрес объекта кучи) копируется на принимающую сторону, может быть достигнут тот же объект кучи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...