Как определить объем стекового пространства, доступного моей программе? - PullRequest
6 голосов
/ 28 августа 2009

Мое приложение Win32 C ++ действует как сервер RPC - оно имеет набор функций для обработки запросов, а среда выполнения RPC создает отдельный поток и вызывает одну из моих функций в этом потоке.

В моей функции у меня есть std :: auto_ptr, который используется для управления массивом char [] размером с кучу, известным во время компиляции. Он работает случайно при компиляции с VC ++ , но это неопределенное поведение в соответствии со стандартом C ++, и я хотел бы от него избавиться.

У меня есть два варианта: std :: vector или выделенный стеком массив. Поскольку я понятия не имею, почему существует массив, выделенный в куче, я хотел бы рассмотреть вопрос о его замене на массив, выделенный стеком. Массив состоит из 10 тыс. Элементов, и я могу гипотетически столкнуться с переполнением стека, если среда выполнения RPC порождает поток с очень маленьким стеком.

Я хотел бы определить, сколько стекового пространства типично выделено для потока и сколько его доступно моей функции (его вызывающие, безусловно, занимают часть выделенного пространства). Как я мог это сделать?

Ответы [ 5 ]

9 голосов
/ 28 августа 2009

Я не знаю какого-либо способа определить размер стека напрямую с помощью API, если у вас нет доступа к вызову CreateThread или, если это основной поток, посмотреть размер потока по умолчанию в EXE-файле в PE заголовок.

В вашей ситуации я бы выделил кучу для безопасности, хотя массив небольших данных размером 10 КБ вряд ли будет максимизировать стек в нерекурсивных сценариях.

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

В этой статье о КБ описывается, как декомпозировать стековую память и восстановить защитную страницу. Она исследует с использованием рекурсии и приращений по 10 000 байт; по умолчанию компилятор реализует свой собственный анализ стека для локальных выделений> 4 КБ, чтобы механизм роста стека работал правильно.

3 голосов
/ 28 августа 2009

В Windows размер стека по умолчанию составляет 1 МБ, поэтому маловероятно, что стек будет переполнен только массивом 10 КБ. Тем не менее, я думаю, что выделение такого большого количества памяти в стеке - плохая практика, и вы должны попытаться выделить ее динамически, если можете. Существует также Scoped Array , который хорошо определен для автоматического управления массивами - в отличие от класса vector, он не копируется.

1 голос
/ 28 августа 2009

I секунда 1800 ИНФОРМАЦИЯ:

  • Размещайте свои данные в куче, если можете. Это более безопасно (например, переполнение буфера труднее использовать) и более гибко, когда (не если) вам нужно расширить свой проект позже.

  • Используйте std :: vector, boost :: scoped_array или boost :: shared_array.

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

0 голосов
/ 28 августа 2009

Я не уверен, что вы после.

Если вы хотите просто типичные цифры, тогда попробуйте! Создайте функцию с вложенными областями, каждая из которых выделяет еще немного стекового пространства. Вывод в каждой области. Посмотрите, как далеко это заходит.

Если вам нужны конкретные числа в конкретной ситуации, спросите себя, что бы вы хотели сделать, когда они у вас появятся? Разветвляться на разные реализации? Это звучит как проблема технического обслуживания, использование которой должно быть очень хорошо оправдано. Что вы ожидаете получить? Это действительно стоит таких хлопот?

Я согласен, что 10k обычно не должно быть проблемой. Так что, если ваш код не является критически важным, продолжайте и используйте boost::array (или std::tr1::array, если ваш std lib поставляется с ним). В противном случае просто используйте std::vector или, если считаете, что нужно, boost::scoped_array (или std::tr1::scoped_array, если ваша стандартная библиотека поставляется с ним)

0 голосов
/ 28 августа 2009

"std :: auto_ptr, который используется для управлять распределенным в куче символом [] ... это неопределенное поведение в соответствии с C ++ "

Это неверное предположение! STL auto_ptr имеет точное описание поведения. Если вы беспокоитесь о потере контроля во время сложной проверки присваивания, вы можете использовать шаблон счетчика ссылок для управления уничтожением выделенного массива кучи.

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