Освобождение выделенной памяти - PullRequest
7 голосов
/ 12 ноября 2008

Можно ли освободить память, явно выделенную C в alloca (), до выхода из текущей функции? Если да, то как?

Ответы [ 7 ]

9 голосов
/ 12 ноября 2008

С http://www.gnu.org/software/libc/manual/html_mono/libc.html#Variable-Size-Automatic:

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

8 голосов
/ 12 ноября 2008

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

Но мне трудно поверить, что это стоило того. Просто используйте malloc / free, если вам нужно явно освободить его - эти функции обычно сильно оптимизированы. Воспользуйтесь ими.

3 голосов
/ 15 апреля 2015

Используя C99, вы можете достичь того же, используя Массив переменной длины . Просто объявите VLA в новой области; он будет автоматически освобожден при выходе из области действия.

Например:

int some_function(int n) {
    // n has the desired length of the array
    ...
    { // new scope
        int arr[n]; // instead of int *arr = alloca(n*sizeof(int));
        // do stuff with array
    }
    // function continues with arr deallocated
    ...
}
3 голосов
/ 12 ноября 2008

Вы размещаете в стеке с помощью alloca (); Если что-то еще произошло потом (и вы не можете контролировать это, не записав все в сборку), вы не можете просто сжать стек обратно. Поэтому, пока вы не покинете фрейм стека своей функции, это невозможно.

Это также, почему вы можете действительно испортить ситуацию, если переполните выделенный буфер. Вы можете начать переписывать адреса кода, к которому возвращается ваша функция, заставляя ее прыгать куда-то еще, всякого рода ужасные вещи. Будь осторожен!

Malloc работает в куче, поэтому он гораздо более гибок в своих действиях.

1 голос
/ 06 июля 2016

Да, но это зависит от реализации alloca (). Разумная и простая реализация alloca () заключается в том, что вновь выделенный блок помещается в верх стека путем настройки указателя стека. Поэтому, чтобы освободить эту память, нам нужно только сделать отрицательное распределение (но вам нужно изучить реальную реализацию alloca ()), давайте проверим это, взяв следующую непереносимую код например:

#include <stdio.h>
#include <alloca.h>

int main()
{
  unsigned long p0, p1, p2;
  p0=(unsigned long)alloca(0);
  p1=(unsigned long)alloca((size_t) 0x1000);
  p2=(unsigned long)alloca((size_t)-0x1000);
  printf( "p0=%lX, p1=%lX, p2=%lX\n", p0, p1, p2 );
  return 0;
}

На старой машине x64 с clang 2.9 пример вывода:

p0=7FFF2C75B89F, p1=7FFF2C75A89F, p2=7FFF2C75B89F

Итак, мы знаем, что реализация не проверяет аргумент -0x1000, в противном случае значение без знака будет очень большим целым числом. Первоначально указатель стека был 0x ... B89F; поскольку этот стек увеличивается в сторону увеличения (0x1000), поэтому измените указатель стека up на (0x ... B89F - 0x1000) = 0x ... A89F. После отрицательного распределения (0xA89F - (-0x1000)) указатель стека вернулся к 0x ... B89F.

Однако, с gcc 4.8.3, пример вывода:

p0=7FFFA3E27A90, p1=7FFFA3E26A80, p2=7FFFA3E27A70

В /usr/include/alloca.h мы нашли:

#ifdef  __GNUC__
# define alloca(size)   __builtin_alloca (size)
#endif /* GCC.  */

Итак, мы знаем, что встроенная функция alloca, предоставляемая gcc 4.8.3, сделала то же самое, за исключением того, что она выделяла дополнительные 0x10 байтов в качестве запаса прочности. При выполнении отрицательного распределения все равно предполагается, что оно растет вверх и поэтому пытается зарезервировать 0x10 дополнительных байтов (- 0x10), поэтому p2 = 0x ... 6A80 - (-0x1000) - 0x10 = 0x ... 7A70. Так что будьте особенно осторожны.

1 голос
/ 04 апреля 2014

Это было бы полезно для стиля прохождения продолжения (CPS), а не для реаллока.

Вы можете вызвать функцию, которая выделяет и манипулирует строкой в ​​верхней части стека, перед тем как уменьшить размер стека до длины строки и вызвать следующую функцию.

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

1 голос
/ 12 ноября 2008

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

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

...