2009-11-07 3 views
8

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

Здесь я предполагаю среду linux (gcc-компилятор) с архитектурой x86.

ответ

2

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

gcc имеет отличную сборку, в отличие от некоторых чешуек.

+0

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

+0

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

+0

Это не так просто, как «они растут напротив друг друга» , glibc может просто использовать mmap() для запроса дополнительной области виртуальной памяти, и теоретически может жить в любом месте в адресном пространстве виртуальной памяти, поэтому malloc() не обязательно будет использовать пространство, которое будет использоваться стеком. Метод выделения, используемый glibc для malloc(), может варьироваться в зависимости от многих факторов (например, он может использовать sbrk(), или он может использовать mmap()). – ehabkost

0

Это очень зависит от вашей ОС и управления памятью. В Linux вы можете использовать procfs. Это что-то вроде/proc/$ PID/memory. Сейчас я не на Linux.

GCC обычно добавляет 16 бит для регистров (чтобы вернуться к контексту функции, указанному) в стек кадров. Обычно вы можете получить дополнительную информацию о том, как программа точно скомпилирована путем ее дизассемблирования. Или используйте -S, чтобы получить сборку.

0

Если ваше приложение должно быть уверенным, что оно может использовать X МБ памяти, обычный подход заключается в том, чтобы процесс мог назначить его во время запуска (и не запускаться, если он не может выделить минимальное требование).

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

+0

@diciu, я хотел знать о памяти в стеке, а не динамически выделяемой памяти. Стек распределяется по системе и размеру исправления. –

+0

Это не фиксированный размер. См. Ulimit - он позволяет вам контролировать размер стека, который ОС назначает процессу. – diciu

0

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

1

Вы можете увидеть состояние области виртуальной памяти стека, взглянув на /proc/<pid>/smaps. Стек vma автоматически растет, когда вы используете больше спа стека. Вы можете проверить, сколько стекового пространства вы действительно используете, проверяя, как далеко %esp находится с верхнего предела области стека на smaps (по мере того, как стек растет). Вероятно, первый предел, который вы нажмете, если вы используете слишком много пространства для стека, будет таким же, как у ulimit.

Но всегда помните, что эти детали низкого уровня могут отличаться без какого-либо уведомления. Не ожидайте, что все версии ядра Linux и все версии glibc будут иметь одинаковое поведение. Я бы никогда не заставлял свою программу полагаться на эту информацию.

+0

Заметьте, я говорю только о Linux на x86. – ehabkost

5

Существует API-нитей, чтобы определить, где находится стек:

#include <pthread.h> 

void PrintStackInfo (void) 
    { pthread_attr_t Attributes; 
     void *StackAddress; 
     int StackSize; 

    // Get the pthread attributes 
    memset (&Attributes, 0, sizeof (Attributes)); 
    pthread_getattr_np (pthread_self(), &Attributes); 

    // From the attributes, get the stack info 
    pthread_attr_getstack (&Attributes, &StackAddress, &StackSize); 

    // Done with the attributes 
    pthread_attr_destroy (&Attributes); 

    printf ("Stack top:  %p\n", StackAddress); 
    printf ("Stack size: %u bytes\n", StackSize); 
    printf ("Stack bottom: %p\n", StackAddress + StackSize); 
    } 

На i386, стек начинается в нижней части и растет по направлению к вершине.

Итак, вы знаете, что у вас есть ($ ESP - StackAddress) байты.

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

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

Смежные вопросы