Чи можна визначити, скільки місця на стеку?

Я розробляю невеликий програмний движок, і я хотів би дорого використовувати стек для швидких ітерацій великої кількості наборів. Але тоді мені прийшло в голову, що це може бути поганою ідеєю, оскільки стек не є таким великим, як сховище пам'яті. Але мене приваблює швидкість стеку і відсутність динамічного кодування.

Чи є спосіб дізнатися, як далеко я можу натиснути стек на даній платформі? Я дивлюся в основному на мобільні пристрої, але проблема може виникнути на будь-якій платформі.

11
Або динамічно, або взагалі взагалі, щоб дізнатися, як далеко можна пересунути стек перед переповненням. Не обов'язково під час виконання, але якщо є інструменти, якимось чином отримають цю інформацію. Звичайно, час виконання теж непоганий.
додано Автор johnbakers, джерело
Не дублікат, але перегляньте stackoverflow.com/q/1756285/1729885
додано Автор Niels Keurentjes, джерело
Таким чином, ви хочете динамічно (тобто під час виконання) визначити розмір стека?
додано Автор ComFreek, джерело
Зверніть увагу, що часто ви можете перетворити рекурсивний алгоритм на ітераційний алгоритм, утримуючи стек на стороні (виділеному в купі). У C ++ цей стек може бути або стек , або deque (залежно від того, чи хочете ви LIFO або FIFO) без ручного ведення бухгалтерського обліку та надмірно зазвичай досить низький; на системі, обмеженій стеком, я б рекомендував її.
додано Автор Matthieu M., джерело
Зверніть увагу, що часто ви можете перетворити рекурсивний алгоритм на ітераційний алгоритм, утримуючи стек на стороні (виділеному в купі). У C ++ цей стек може бути або стек , або deque (залежно від того, чи хочете ви LIFO або FIFO) без ручного ведення бухгалтерського обліку та надмірно зазвичай досить низький; на системі, обмеженій стеком, я б рекомендував її.
додано Автор Matthieu M., джерело
Зауважте, що більшість компіляторів дозволяють визначити розмір стека, коли ви компілюєте код. Отже, якщо у вас є верхня межа у використанні стека, ви можете сказати компілятору використовувати "your_upper_bound + деяке розумне значення для того, що ще потрібно буде перейти в стек (можливо, тільки початковий розмір стека за замовчуванням)".
додано Автор Jesper Juhl, джерело
Зауважте, що більшість компіляторів дозволяють визначити розмір стека, коли ви компілюєте код. Отже, якщо у вас є верхня межа у використанні стека, ви можете сказати компілятору використовувати "your_upper_bound + деяке розумне значення для того, що ще потрібно буде перейти в стек (можливо, тільки початковий розмір стека за замовчуванням)".
додано Автор Jesper Juhl, джерело
Я не думаю, що є будь-яке загальне рішення. і розмір стека може відрізнятися між різними потоками
додано Автор Bryan Chen, джерело
Якщо швидке виділення є вимогою, і у вас є шаблон виділення, подібний до стека, і ви знаходитесь на Linux, ви можете використовувати перешкоди glibc: html_node/Obstacks.html "rel =" nofollow "> gnu.org/software/libc/manual/html_node/Obstacks.html
додано Автор Alexandre C., джерело
Якщо швидке виділення є вимогою, і у вас є шаблон виділення, подібний до стека, і ви знаходитесь на Linux, ви можете використовувати перешкоди glibc: html_node/Obstacks.html "rel =" nofollow "> gnu.org/software/libc/manual/html_node/Obstacks.html
додано Автор Alexandre C., джерело

10 Відповіді

На * nix скористайтеся getrlimit :

   RLIMIT_STACK
          The maximum size of the process stack, in bytes.  Upon
          reaching this limit, a SIGSEGV signal is generated.  To handle
          this signal, a process must employ an alternate signal stack
          (sigaltstack(2)).

У Windows скористайтеся VirtualQuery :

Для першого виклику передайте адресу будь-якого значення в стек   отримують базову адресу і розмір, у байтах, відданого простору стека.   На машині x86, де стек зростає вниз, відніміть розмір   з базової адреси та VirtualQuery знову: це дасть вам   розмір простору, зарезервованого для стека (якщо ви не   точно на межі розміру стека в той час). Підсумовуючи два   природно дає загальний розмір стека.

Існує не незалежний від платформи метод, оскільки розмір стека залишається для реалізації, а хост-система логічно - на вбудованому міні-SOC є менше ресурсів для розповсюдження, ніж на 128 Гб оперативної пам'яті. Проте ви можете впливати на розмір стека конкретного потоку на всіх ОС, а також на виклики, специфічні для API.

7
додано

На * nix скористайтеся getrlimit :

   RLIMIT_STACK
          The maximum size of the process stack, in bytes.  Upon
          reaching this limit, a SIGSEGV signal is generated.  To handle
          this signal, a process must employ an alternate signal stack
          (sigaltstack(2)).

У Windows скористайтеся VirtualQuery :

Для першого виклику передайте адресу будь-якого значення в стек   отримують базову адресу і розмір, у байтах, відданого простору стека.   На машині x86, де стек зростає вниз, відніміть розмір   з базової адреси та VirtualQuery знову: це дасть вам   розмір простору, зарезервованого для стека (якщо ви не   точно на межі розміру стека в той час). Підсумовуючи два   природно дає загальний розмір стека.

Існує не незалежний від платформи метод, оскільки розмір стека залишається для реалізації, а хост-система логічно - на вбудованому міні-SOC є менше ресурсів для розповсюдження, ніж на 128 Гб оперативної пам'яті. Проте ви можете впливати на розмір стека конкретного потоку на всіх ОС, а також на виклики, специфічні для API.

7
додано

Можливим портативним рішенням є написання розподільника самостійно Вам не потрібно використовувати стек процесу, просто імітуйте його в купі.
Спочатку виділіть великий об'єм пам'яті, а над ним напишіть розподільник стека, щоб використовувати його під час розподілу.
Google "Вимоги до розподілу" для отримання інформації про те, як досягти цього в C ++.

Я не впевнений, що термін "розподільник стеків" є канонічним, але я маю на увазі, що ви повинні покласти обмеження на стек, де має відбутися розподіл або звільнення.
Оскільки ви сказали, що ваш алгоритм підходить для цієї моделі, я думаю, що це буде легко.

5
додано

Можливим портативним рішенням є написання розподільника самостійно Вам не потрібно використовувати стек процесу, просто імітуйте його в купі.
Спочатку виділіть великий об'єм пам'яті, а над ним напишіть розподільник стека, щоб використовувати його під час розподілу.
Google "Вимоги до розподілу" для отримання інформації про те, як досягти цього в C ++.

Я не впевнений, що термін "розподільник стеків" є канонічним, але я маю на увазі, що ви повинні покласти обмеження на стек, де має відбутися розподіл або звільнення.
Оскільки ви сказали, що ваш алгоритм підходить для цієї моделі, я думаю, що це буде легко.

5
додано

У стандартному C ++, безумовно, немає. У переносний спосіб, ймовірно, немає. У певній ОС іноді. Якщо нічого іншого, ви можете відкрити власний розмір виконуваного файлу і перевірити заголовки виконуваного файлу, щоб побачити, що він складається. [Наступною проблемою є, звичайно, «яка частина стека була використана до цього біта коду» - що може бути важко визначити].

Якщо ви запускаєте код у окремому потоці, багато з (низькорівневих) інтерфейсів потоків дозволяють вказати стек (або стеки), наприклад, потоки Posix pthread_set_stacksize або MS _beginthread . Знову ж таки, ви не знаєте точно, скільки місця було використано до того, як він потрапив до фактичного коду потоку - але це, мабуть, не величезна кількість.

Звичайно, у вбудованій системі (наприклад, мобільному телефоні) розмір стосів зазвичай досить малий, 4K, 12K або 64KB є дуже нормальним - іноді навіть набагато менше, ніж у деяких системах.

Інша потенційна проблема полягає в тому, що ви не можете знати, скільки простору використовується в стеку - ви можете виміряти за фактом у компільованій системі, і, звичайно, якщо у вас є локальний масив стека int масиву [ 25]; , ми можемо знати, що він займає принаймні 25 * sizeof (int) - але може бути заповнення, компілятор зберігає регістри в стеку і т.д.

Редагувати, як запізнення: Я також не бачу багато користі від двох кодових шляхів:

 if (enough_stack_space_for_something)
      use_stack_based_algorithm();
 else
      use_heap_based_algorithm();

Це додасть велику кількість додаткових накладних витрат, і більше коду, як правило, не є хорошим планом у вбудованій/мобільній системі.

Edit2: Крім того, якщо виділення пам'яті є основною частиною середовища виконання, можливо, дивлячись на те, що це, наприклад, створення блоків об'єктів, допоможе?

2
додано

У стандартному C ++, безумовно, немає. У переносний спосіб, ймовірно, немає. У певній ОС іноді. Якщо нічого іншого, ви можете відкрити власний розмір виконуваного файлу і перевірити заголовки виконуваного файлу, щоб побачити, що він складається. [Наступною проблемою є, звичайно, «яка частина стека була використана до цього біта коду» - що може бути важко визначити].

Якщо ви запускаєте код у окремому потоці, багато з (низькорівневих) інтерфейсів потоків дозволяють вказати стек (або стеки), наприклад, потоки Posix pthread_set_stacksize або MS _beginthread . Знову ж таки, ви не знаєте точно, скільки місця було використано до того, як він потрапив до фактичного коду потоку - але це, мабуть, не величезна кількість.

Звичайно, у вбудованій системі (наприклад, мобільному телефоні) розмір стосів зазвичай досить малий, 4K, 12K або 64KB є дуже нормальним - іноді навіть набагато менше, ніж у деяких системах.

Інша потенційна проблема полягає в тому, що ви не можете знати, скільки простору використовується в стеку - ви можете виміряти за фактом у компільованій системі, і, звичайно, якщо у вас є локальний масив стека int масиву [ 25]; , ми можемо знати, що він займає принаймні 25 * sizeof (int) - але може бути заповнення, компілятор зберігає регістри в стеку і т.д.

Редагувати, як запізнення: Я також не бачу багато користі від двох кодових шляхів:

 if (enough_stack_space_for_something)
      use_stack_based_algorithm();
 else
      use_heap_based_algorithm();

Це додасть велику кількість додаткових накладних витрат, і більше коду, як правило, не є хорошим планом у вбудованій/мобільній системі.

Edit2: Крім того, якщо виділення пам'яті є основною частиною середовища виконання, можливо, дивлячись на те, що це, наприклад, створення блоків об'єктів, допоможе?

2
додано

Щоб розширити відповіді, вже сказані про те, чому немає портативного способу зробити це, вся концепція фактичного стека не є частиною стандарту. Ви можете написати середовище виконання C або C ++, яке не використовує стек на всіх, окрім записів викликів функцій (які можуть бути внутрішнім списком або іншим).

Стек - це деталь реалізації конкретної машини/ОС/компілятора. Отже, будь-яка техніка доступу до метрик стека буде специфічною для машини/ОС/компілятора.

Хоча це не є реальною відповіддю на ваше конкретне запитання (Нілс охоплює це досить добре), але як порада для вашої проблемної області: просто виділіть великий кусок пам'яті в купі. Немає жодних причин, за винятком зручності, що "справжній" стек відрізняється. Алгоритми з високою рекурсією (без рекурсії) часто повинні робити це, щоб переконатися, що вони мають практично необмежений "стек". Мови сценаріїв, які хочуть переконатися, що вони надають помилку/виключення під час виконання, а не руйнують хост-програму, також часто це роблять. Щоб бути ефективним щодо речей, ви можете або реалізувати "розділений стек" (як std :: deque дасть вам), або ви можете просто бути впевнені, що preallocate стек досить великий для ваших потреб.

2
додано
Існує немає причин, крім зручності, що "справжній" стек відрізняється. Але часто згадується, що стек швидше, ніж купа, так що, звичайно, це більше, ніж зручність?
додано Автор johnbakers, джерело
Розподіл (використовуючи malloc або новий або подібні) на купі повільніше, ніж створювати локальну змінну в стеку або використовувати щось подібне <�код >. Стек у більшості випадків автоматично уникає проблем фрагментації та кеш-локальності, які можуть вас укусити, якщо ви наївні, але які не є проблемою, якщо ви обережні. Деякі архітектури мають явні інструкції для реалізації стека, наприклад. натисніть і pop на x86, але їх переваги будуть вкрай мінімальними в більшості алгоритмів. Якщо у вас немає номерів продуктивності, які вам доведеться, не хвилюйтеся про це.
додано Автор Sean Middleditch, джерело

Щоб розширити відповіді, вже сказані про те, чому немає портативного способу зробити це, вся концепція фактичного стека не є частиною стандарту. Ви можете написати середовище виконання C або C ++, яке не використовує стек на всіх, окрім записів викликів функцій (які можуть бути внутрішнім списком або іншим).

Стек - це деталь реалізації конкретної машини/ОС/компілятора. Отже, будь-яка техніка доступу до метрик стека буде специфічною для машини/ОС/компілятора.

Хоча це не є реальною відповіддю на ваше конкретне запитання (Нілс охоплює це досить добре), але як порада для вашої проблемної області: просто виділіть великий кусок пам'яті в купі. Немає жодних причин, за винятком зручності, що "справжній" стек відрізняється. Алгоритми з високою рекурсією (без рекурсії) часто повинні робити це, щоб переконатися, що вони мають практично необмежений "стек". Мови сценаріїв, які хочуть переконатися, що вони надають помилку/виключення під час виконання, а не руйнують хост-програму, також часто це роблять. Щоб бути ефективним щодо речей, ви можете або реалізувати "розділений стек" (як std :: deque дасть вам), або ви можете просто бути впевнені, що preallocate стек досить великий для ваших потреб.

2
додано
Існує немає причин, крім зручності, що "справжній" стек відрізняється. Але часто згадується, що стек швидше, ніж купа, так що, звичайно, це більше, ніж зручність?
додано Автор johnbakers, джерело
Розподіл (використовуючи malloc або новий або подібні) на купі повільніше, ніж створювати локальну змінну в стеку або використовувати щось подібне <�код >. Стек у більшості випадків автоматично уникає проблем фрагментації та кеш-локальності, які можуть вас укусити, якщо ви наївні, але які не є проблемою, якщо ви обережні. Деякі архітектури мають явні інструкції для реалізації стека, наприклад. натисніть і pop на x86, але їх переваги будуть вкрай мінімальними в більшості алгоритмів. Якщо у вас немає номерів продуктивності, які вам доведеться, не хвилюйтеся про це.
додано Автор Sean Middleditch, джерело

Немає стандартного способу зробити це з мови. Я навіть не знаю про документальне розширення, яке може запитувати.

Однак деякі компілятори мають опції для встановлення розміру стека. І платформа може вказати, що вона робить під час запуску процесу, та/або передбачити способи встановлення розміру стека нової нитки, можливо, навіть маніпулювати існуючим.

Для невеликих платформ звичайно знають весь розмір пам'яті, мають всі сегменти даних на одному кінці, арену розміру набору для купи (може бути 0), а решта - стек, наближаючись з іншої сторони.

1
додано

Немає стандартного способу зробити це з мови. Я навіть не знаю про документальне розширення, яке може запитувати.

Однак деякі компілятори мають опції для встановлення розміру стека. І платформа може вказати, що вона робить під час запуску процесу, та/або передбачити способи встановлення розміру стека нової нитки, можливо, навіть маніпулювати існуючим.

Для невеликих платформ звичайно знають весь розмір пам'яті, мають всі сегменти даних на одному кінці, арену розміру набору для купи (може бути 0), а решта - стек, наближаючись з іншої сторони.

1
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147