2011-08-16 30 views
20

Pregunta simple sobre la función realloc en C: Si uso realloc para reducir el bloque de memoria al que apunta un puntero, ¿se libera la memoria "extra"? ¿O necesita ser liberado manualmente de alguna manera?Uso de realloc para reducir la memoria asignada

Por ejemplo, si hago

int *myPointer = malloc(100*sizeof(int)); 
myPointer = realloc(myPointer,50*sizeof(int)); 
free(myPointer); 

Voy a tener una pérdida de memoria?

+1

Estrictamente hablando hay una pérdida de memoria, ya que no registra el resultado de 'realloc' y por lo tanto no puede liberarlo. Pero como indica la respuesta de R .., puede haber tenido suerte en un detalle de implementación. –

+1

Vaya, tienes razón. Intenté corregirlo ¿Que tal ahora? –

+6

El nuevo código todavía pierde la asignación original si falla el 'realloc'. Espero que la mayoría de las implementaciones no dejen de reducir un bloque, pero está permitido. La forma correcta de llamar a realloc, ya sea creciendo o reduciendo el bloque, es 'void * tmp = realloc (myPointer, 50 * sizeof (int)); if (! tmp) {/ * manejar el error de alguna manera. myPointer aún apunta al bloque anterior, que todavía está asignado * /} myPointer = tmp; '. –

Respuesta

16

No, no tendrá una pérdida de memoria. realloc simplemente marcará el resto "disponible" para futuras operaciones malloc.

Pero todavía tiene que freemyPointer más adelante. Como un aparte, si usa 0 como el tamaño en realloc, tendrá el mismo efecto que freeen algunas implementaciones. Como dijeron Steve Jessop y R .. en los comentarios, no deberías confiar en eso.

+3

"si usa 0 como el tamaño en realloc, tendrá el mismo efecto que libre". - puede ser cierto en su implementación, pero no está garantizado. Si 'realloc' devuelve un puntero nulo de una entrada 0, y no configuró errno en ENOMEM, entonces la memoria se liberó. Pero al igual que malloc, realloc puede intentar devolver una asignación real de 0 tamaño utilizable. La implementación es necesaria para documentar cuál (7.20.3/1). –

+2

Steve tiene razón, y la consecuencia práctica de esto es que nunca debe llamar 'realloc' con un tamaño de 0. Tratando con todos los comportamientos posibles, la existencia de implementaciones no conformes, y el hecho de que el C y el POSIX la gente parece estar en desacuerdo sobre lo que está de acuerdo y lo que no es una mala idea para confiar en cualquier cosa relacionada con 'realloc (x, 0)'. –

+0

@Steve Jessop, R .. Gracias por aclarar :-) Nunca me molesté en consultar más allá de POSIX, no sabía que no era estándar. – cnicutar

11

Hay definitivamente no es una pérdida de memoria, pero cualquiera de al menos 3 cosas podría suceder cuando se llama realloc para reducir el tamaño:

  1. La aplicación se divide el bloque de memoria asignada a la nueva longitud y libre solicitado la porción no utilizada al final.
  2. La aplicación hace una nueva asignación con el nuevo tamaño, copias el contenido anterior a la nueva ubicación, y libera toda la asignación de edad.
  3. La implementación no hace nada en absoluto.

La opción 3 sería una implementación bastante mala, pero perfectamente legal; todavía no hay "pérdida de memoria" porque todo seguirá siendo liberado si luego llama al free.

En cuanto a las opciones 1 y 2, que es mejor depende mucho de si usted favorece el rendimiento o evitar la fragmentación de memoria. Creo que la mayoría de las implementaciones del mundo real se inclinarán hacia hacer la opción 1.

+0

¿Cuál es el razonamiento detrás de la opción 2 cuando necesita ** reducir ** la memoria asignada? No puedo resolverlo. – Jacob

+1

Supongamos que asigna 100 bytes y desea cambiar el tamaño a 50 bytes. La primera asignación reclamó una zona libre de 100 bytes, y la opción 1 devuelve una zona libre de 50 bytes, pero la zona más larga de 100 bytes ya no está disponible. Sin embargo, si hubiera otra zona libre con solo 50 bytes de longitud, la opción 2 podría mover los datos a esa ubicación y liberar una zona de 100 bytes, dejando la memoria menos fragmentada. –

+0

Tenga en cuenta que si su objetivo es optimizar la fragmentación mínima, tiene sentido tomar la opción 2 cuando ya existe una zona libre más pequeña lo suficientemente grande como para contener la asignación. Si tiene que obtener más memoria del sistema o dividir otra zona libre más grande, solo puede empeorar la fragmentación, no mejorar. –

3

En la forma en que usted ha dado su código, sí, podría tener una fuga. La idea de realloc es que puede devolverle una nueva ubicación de sus datos. Al igual que lo haces en tu pregunta, pierdes el puntero que te envía realloc.

int *myPointer2 = realloc(myPointer,50*sizeof(int)); 
assert(myPointer2); 
myPointer = myPointer2; 
+0

@R ... en realidad no estaba tan seguro, es por eso que no me limité a poner en un comentario. Si lo piensas, la manera en que * realmente * hizo su pregunta es mucho más natural preguntarse qué le sucede a la memoria "libre". –

4

El nuevo código todavía pierde la asignación original si el realloc falla. Espero que la mayoría de las implementaciones no dejen de reducir un bloque, pero está permitido. La forma correcta de llamar a realloc, ya sea creciendo o reduciendo el bloque, es void * tmp = realloc (myPointer, 50 * sizeof (int)); if (! tmp) {/ * manejar el error de alguna manera. myPointer aún apunta al bloque anterior, que todavía está asignado * /} myPointer = tmp ;. - Hace Steve Jessop 48 minutos

Hey, no podía encontrar la manera de responder a su comentario, lo siento.

¿Es necesario echar tmp con el tipo de MiPuntero? En este caso, ¿necesito escribir

myPointer = (int*)tmp 

También, en este caso, cuando lo haga libre (MiPuntero) La memoria apuntado por tmp se liberará así, ¿verdad?Entonces no hay necesidad de hacerlo

free(myPointer) 
free(tmp) 
+0

Realloc seguirá teniendo fugas. Esta es la respuesta correcta. Al menos en Windows 7, 64 bit (tdm-gcc64) – dns

Cuestiones relacionadas