Могу ли я вытянуть стек? - PullRequest
4 голосов
/ 27 июля 2010

Я знаю, что с помощью оператора new () я могу исчерпать память и знаю, как защитить себя от такого случая, но могу ли я исчерпать память, создавая объекты в стеке? И если да, как я могу проверить, было ли создание объекта успешным?
Спасибо.

Ответы [ 7 ]

4 голосов
/ 27 июля 2010

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

т.е.

void fun() { fun(); }
4 голосов
/ 27 июля 2010

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

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

Обратите внимание, что существуют способы определения / изменения размера стека.

3 голосов
/ 27 июля 2010

Да, вы можете исчерпать стек. В обычных системах аппаратное обеспечение / операционная система перехватывает и прерывает вашу программу. Однако это трудно сделать. Вам придется либо создавать огромные объекты в стеке (автоматические массивы), либо выполнять глубокую рекурсию.

Обратите внимание, что если вы используете общие абстракции, такие как std::string, std::vector и т. Д., Вы вряд ли когда-либо исчерпаете стек, потому что, пока они живут в стеке, у них есть данные в куче. (Это верно для всех контейнеров STL, поставляемых с std lib, за исключением std::tr1::array.)

1 голос
/ 27 июля 2010

Хорошо, но вам понадобятся резкие реакции, чтобы определить, когда «создание объекта» будет успешным.

class MyObject {
private:
   int x
public:
   MyObject() { x = 0; }
};

int main(int argc, char **argv) {
    IWantToExhaustTheStack();
    return 0;
}

void IWantToExhaustTheStack() {
    MyObject o;
    IWantToExhaustTheStack();
}

Теперь скомпилируйте и запустите это, в течение очень короткого времени, пока ваше создание объекта будет работать. Вы будете знать, что создание объекта не удалось, когда ваша программа не удалась.

Шутки в сторону, и в ответ на ваш обновленный вопрос не существует стандартного способа определения размера стека. См .: Этот Stackoverflow Вопрос по отношению к Win32. Однако стек используется для вызова методов и хранения локальных временных и возвращаемых переменных. Если вы размещаете большие объекты в стеке, вам действительно следует подумать о том, чтобы поместить их в кучу.

1 голос
/ 27 июля 2010

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

1 голос
/ 27 июля 2010

Да, смотрите название сайта. Вы не можете реально проверить, что создание объекта прошло успешно - программа просто падает при переполнении стека.

0 голосов
/ 27 июля 2010

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

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

Смотреть рекурсии (не слишком глубоко), смотреть alloca (не слишком много). Смотрите приглядывания при изучении использования стека.

В OpenSolaris есть несколько функций, позволяющих управлять стеком.

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