2008-11-12 6 views
6

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

+0

Не могли бы вы объяснить свою мотивацию? Почему вы хотите освободить выделенное пространство перед возвратом? – Motti 2008-12-07 20:22:08

ответ

8

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

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

+3

Одной из переносимых реализаций является «void freea (void * p) {} // Просто подделаем». – paxdiablo 2008-11-12 06:49:06

1

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

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

2

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

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

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

8

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

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

1

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

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

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

2

Используя C99, вы можете достичь того же, используя Variable Length Array. Просто объявите 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 
    ... 
} 
1

Да, но это зависит от реализации 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 с грохотом 2.9, выход образца:

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

Итак, мы знаем реализацию не проверить аргумент -0x1 000, иначе значение unsigned будет очень большим целым числом. Указатель стека был изначально 0x ... B89F; поскольку этот стек растет вверх alloca (0x1000), поэтому измените указатель стека до на (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. Поэтому будьте осторожны.

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