Выдает alloca () память, если выброшено исключение? - PullRequest
0 голосов
/ 14 декабря 2018

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

Вся выделенная память выполняется с помощью alloca (), а не malloc ().Я объяснил это тем, что alloca () работает как сборщик мусора java и автоматически освобождает память при выходе из контекста.

Из-за того, что утечка так явно связана с создаваемыми исключениями, у меня есть теория, что alloca () не освобождает память, когда генерируются исключения.

Это вообще правдоподобно?Мне кажется, что это серьезный дефект в alloca (), если он истинен, но когда я запускаю Google alloca (), это, как правило, является проблемой.

Буду признателен за понимание любых экспертов.

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

Из Linux man

....

Поскольку пространство, выделенное alloca (), выделяется в кадре стека, это пространство автоматическиосвобождается , если функция, возвращающая , перепрыгивается при вызове longjmp (3) или siglongjmp (3).

....

Встроенный код часто состоит изединственная инструкция, регулирующая указатель стека, и не проверяющая переполнение стека.Таким образом, возврат ошибки NULL отсутствует.

.....

Ошибки Нет индикации ошибок , если кадр стека не может бытьпродлен.(Однако после неудачного выделения программа, вероятно, получит сигнал SIGSEGV , если попытается получить доступ к нераспределенному пространству.) Во многих системах alloca () не может использоваться внутри списка аргументов функциивызов, потому что пространство стека, зарезервированное для alloca (), появится в стеке в середине пространства для аргументов функции.

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

0 голосов
/ 14 декабря 2018

Вероятно, проблема связана с уровнем косвенности.

Дословный вопрос: "alloca возвращает память, если выброшено исключение?".И ответ на это есть;Возвращает только память, которая была выделена напрямую.Деструкторы не запускаются, и любой указатель-владелец внутри выделенной памяти alloca просачивается.

0 голосов
/ 14 декабря 2018

В C ++ вы не должны использовать процедуры управления памятью C.В современном C ++ интеллектуальные указатели предоставляют вам мелкозернистую детерминированную сборку мусора.

Хотя пространство, выделенное с помощью alloca(), вероятно, освобождается от исключений (потому что это обычно делается путем увеличения размера текущего кадра стека),Это не является частью стандарта, и поэтому я не думаю, что вы можете дать какие-либо гарантии.

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

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

Код выглядит так:

void func()
{
    MyType* x = (MyType*)alloca(sizeof(MyType));

    passXtoCFunctionThatDoesNotTakeOwnership(x);
}

Должно быть написано так:

void func()
{
    std::unique_ptr<MyType> x = std::make_unique<MyType>();

    passXtoCFunctionThatDoesNotTakeOwnership(x.get());
}

Если вы используете его для хранения массива объектов.

void func()
{
    MyType* x = (MyType*)alloca(sizeof(MyType) * arraySize);

    // STUFF
    x[0].stuff();
}

Тогда лучше использовать std :: vector

void func()
{
    std::vector<MyType> x;
    x.reserve(arraySize);   // or resize() if that is appropriate

    // STUFF
    x[0].stuff();
}

Если вы используете его для простогообъекты.Тогда вам, вероятно, следует просто объявить автоматические переменные:

void func()
{
    MyType* x = (MyType*)alloca(sizeof(MyType));

    x->myData = 5;
}

Вы должны просто объявить переменную:

void func()
{
    MyType x;

    x.myData = 5;
}
...