выделенная память стека против динамически выделяемой памяти - PullRequest
3 голосов
/ 07 января 2012

gcc 4.6.2 c89

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

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

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

Имеет ли вышесказанное смысл для кого-либо?

Большое спасибо за любые предложения,

Ответы [ 4 ]

4 голосов
/ 07 января 2012

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

(Как исключение, статическое распределение данных const не является проблемой.)

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

3 голосов
/ 07 января 2012

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

Если вас беспокоят утечки, статическое распределение упрощает жизнь - вам не нужно ее освобождать, поэтому она не может течь.

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

3 голосов
/ 07 января 2012

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

Я бы сказал, что вам лучше исправить источник повреждения: вы можете использовать gdb для установки точки останова при записи в поврежденную переменную с помощью watch <varname>.Кроме того, вы можете также поставить точку останова при обнаружении повреждения, а затем использовать обратная отладка , чтобы найти, где произошло повреждение.


Редактировать: Кажется, есть некоторая путаница относительно значения стека и static распределение:

void foo() {
    int a[10]; // stack
    static int b[10]; // static

    int *c = malloc(sizeof(int) * 10); // dynamic on the heap
}

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

Статические переменные внутри функции действительны и вне функции - данные хранятся вокругмежду вызовами функций.Это означает, что если вы сделаете это:

void foo() {
    static int a = 0;
    a++;
    printf("%d\n",a);
}

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

Куча переменные действительны с момента их создания и до'1034 * d.Это также называется динамическое выделение и это то, что вам нужно, если вы планируете возвращать данные в другую часть программы (или если вы хотите указать длину массива во время выполнения в C89).


В сторону: static сбивает с толку, поскольку при применении к имени функции или переменной в глобальной области видимости:

static void foo() { ... }
static int x;

это означает, что «эта функция или переменная видна только внутриэтот переводческий блок ".Я не уверен, почему ключевое слово static имеет два разных значения.

2 голосов
/ 07 января 2012

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

Правильно, вы делаете это хорошо.

Объяснение: когда вы выделяете память статически, в стеке / куче / в зависимости от того, что ваша система использует внутри функции, эта память будет доступнапока функция не вернется.Если вы передадите его другой функции, она будет действительной, как если бы, например, function_a создала массив / структуру и вызвала function_b, function_a еще не вернулась, поэтому массив действителен.Так же выглядит следующее:

int function_b(char *buf); /* whatever it does */

int function_a() {
    char array[30];
    /* fill "array" */
    function_b(array); /* valid as this is yet inside this function */
    return 0;
}

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

char *function_a_segfaulty() {
   char array[30];
   do_some_stuff();
   return array; /* INCORRECT: array is now invalid, as the function has returned */
}

Это тот случай, когда вам нужно, чтобы malloc () запустил буфер и возвратил его.Malloc () запрашивает у ОС память и возвращает независимый от функции указатель на ее начало, поэтому функции проходят, и эта память все еще действует .Приведенный выше пример должен быть выполнен следующим образом:

char *function_a_correct() {
   char *array = malloc(30);
   do_some_stuff();
   return array; /* correct */
}

Но в этом случае вам нужно подумать об освобождении этого массива.Обычной практикой является документирование того, что возвращаемое значение этой функции должно быть free () 'd, и пусть вызывающая функция делает это.

Надеюсь, это поможет.

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