У меня очень большая C-программа для молекулярной динамики. Он работает правильно с N = 10000 частиц. Когда я увеличиваю частицы до N = 100000 путем увеличения размера переменной, это вызывает ошибку сегментации.

Я выполнил ulimit -s unlimited, и проблема была решена.

< Сильный > Q1 . Есть ли способ проверить, сколько стековой памяти будет использовать мой код, проверка производительности кода (оптимизация), утечка памяти.

< Сильный > Q2 . Если структура моего кода похожа, вложенные функции,

int main() {
    function1();
    return 0;
}

void function1() {
    for(int i=0;i<1000;i++) {
        function2();
    }
}

void function2() { 
    double Var[100000];
}

Будет ли использование function2() внутри цикла for использовать больше стековой памяти, чем выполнять его только один раз?

c
1
yasir 1 Май 2019 в 19:26

3 ответа

Лучший ответ

Q1 . Я хочу знать, есть ли способ проверить, сколько стековой памяти будет использовать мой код, проверка производительности кода (оптимизация), утечка памяти.

На самом деле, нет. Стандарт C даже не упоминает стек, и любой компилятор C может создавать двоичные файлы, которые не используют стек и при этом соответствуют стандарту C.

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

Производительность не должна быть предсказана. Это следует измерить, а затем оптимизировать при необходимости.

Компилятору очень трудно, если не невозможно, обнаружить утечки памяти надежным способом. Вы можете использовать такие программы, как Valgrind для этого.

Q2 . если структура моего кода похожа на вложенные функции, то из-за вызова function2 внутри цикла for он будет использовать больше стековой памяти, чем один раз?

Нет. Каждый раз, когда вызывается function2(), создается новый стековый кадр с достаточным пространством для 100000 дублей. Но он будет освобожден сразу же, когда функция вернется. Проблема здесь не в том, чтобы вызывать функцию в цикле. Проблема в том, что вы размещаете ОГРОМНЫЕ массивы в стеке, что может стать проблемой. Вам следует рассмотреть возможность их динамического распределения. В основном это будет выглядеть так:

void function2
{
    double *var = malloc(100000*sizeof(*var));
    /* Code */
    free(var);
}

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

unsigned long long sum(unsigned long long num)
{
    if(num == 0) return num;
    return num + sum(n-1);
}

long long обычно составляет 8 байт, поэтому, если вы используете эту функцию для очень большого числа (возможно, 100000 или 1000000), вы можете столкнуться с проблемами стека.

3
user3386109 1 Май 2019 в 17:47

< Сильный > Q1 . Я хочу знать, есть ли способ проверить, сколько стековой памяти будет использовать мой код, проверка производительности кода (оптимизация), утечка памяти.

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

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

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

< Сильный > Q2 . если структура моего кода похожа, вложенные функции, [ ... ] из-за вызова function2 внутри цикла он будет использовать больше стековой памяти, чем один раз?

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

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

2
John Bollinger 1 Май 2019 в 17:27

Лучше не создавать большие объекты в стеке. Вместо этого они должны динамически размещаться с malloc в C или new в C ++.

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

Используя новые интеллектуальные указатели в C ++, вы можете обеспечить освобождение всех выделений и отсутствие утечек, в противном случае вам просто нужно «тщательно написать свой код», что является недостатком программирования на C.

0
Gem Taylor 1 Май 2019 в 18:34