Discussion:
[C] Limpieza de basura...
(demasiado antiguo para responder)
Han Solo
2003-08-14 11:35:01 UTC
Permalink
Hola a todos.

Supongamos que tengo algo como esto

- -----8<-------8<-------8<-------8<-------8<-------8<-------8<-------

struct vector_float {
int nelems;
float *f;
};

struct curva {
int nelems;
float *x;
float *y
};

struct vector_float *inicia_vector (int);
struct curva *inicia_curva(struct vector_float *,struct vector_float *);

int main(){

struct vector_float *x,*y;
struct curva curva*;

x=inicia_vector(15);
y=inicia_vector(10);

curva=inicia_curva(x,y);

free(curva);
free(x);
free(y);

exit(0);
}


struct vector_float *inicia_vector(int n)
{
int i;
float *p;
struct vector_float *resultado;
resultado=(struct vector_float *)malloc(sizeof(*resultado));
p=(float *)malloc(n*sizeof(*p));

for (i=0;i<n;i++){
&p[i]=i/13; //por ejemplo,para que salga un float
}
resultado->f=p;
resultado->nelems=n;
return resultado;
}

struct curva *inicia_curva(struct vector_float vf_x*,struct
vector_float vf_y*)
{

struct curva *resultado;

resultado=(struct curva *)malloc(sizeof(resultado *));
resultado->nelems=vf_y->nelems;
resultado->x=vf_x->f;
resultado->y=vf_y->v;
return resultado;
}

- -----8<-------8<-------8<-------8<-------8<-------8<-------8<-------

Tengo un programa lleno de lindezas como estas, de estructuras
anidadas, y que van generando miles de estructuras como curva a lo
largo de la ejecución. El problema es que creo que el free no hace
nada. Sospecho que tendría que ir liberando hasta los 'arrays' de
'floats' que son los que finalmente ocupan la memoria, Pero tampoco
estoy seguro de esto.

Me gustaría saber si hay una manera de liberar todo de golpe; no me
aptece nada ponerme a hacer las funciones de limpieza...

P.S. Si a alguien le extrañan los 'cast' explícitos al llamar a
malloc(), es porque, aunque el programa está claramente desarrollado
en C, lo estoy compilando con el g++, ya que son funciones que luego
van en un programa en C++.

Gracias a todos por anticipado.

Un Saludo
- --
Han Solo
The Rebel Alliance

Emacs is not on every system

So what? [...] Do you tell your administrative people to stick with
notepad.exe? Do you tell your fat kids they can only have the crummy
games that come with the video games or plain dress that comes with
Barbie?
Fernando Arbeiza
2003-08-14 12:09:12 UTC
Permalink
Post by Han Solo
Me gustaría saber si hay una manera de liberar todo de golpe; no me
aptece nada ponerme a hacer las funciones de limpieza...
Hasta donde yo sé, no la hay, tienes que liberar toda la memoria que has
solicitado. Así que creo que no te queda más remedio que escribir las
funciones de limpieza:

void free_vector (struct vector_float *el_vector);
void free_curva(struct curva *la_curva);

Ni siquiera puedes estar seguro de que al terminar el programa la
memoria solicitada se libere, así que lo mejor que puedes hacer es
hacerlo a mano.

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
Han Solo
2003-08-14 13:42:49 UTC
Permalink
Post by Fernando Arbeiza
Hasta donde yo sé, no la hay, tienes que liberar toda la memoria que has
solicitado. Así que creo que no te queda más remedio que escribir las
Arggg, me lo temía.
Post by Fernando Arbeiza
void free_vector (struct vector_float *el_vector);
void free_curva(struct curva *la_curva);
¿estpo podría ser asi?

void free_curva struct vector_float *el_vector)
{
free(la curva->x);
free(la_curva->y);
}

Porque tengo estructuras que no anidan estructuras completas, sino
partes; como en el ejemplo que os puse,

Gracias por la respuesta.

Un Saludo
- --
Han Solo
The Rebel Alliance

Emacs is not on every system

So what? [...] Do you tell your administrative people to stick with
notepad.exe? Do you tell your fat kids they can only have the crummy
games that come with their video games or plain dress that comes with
Barbie?
Han Solo
2003-08-14 15:39:45 UTC
Permalink
Post by Han Solo
¿estpo podría ser asi?
void free_curva struct vector_float *el_vector)
{
free(la curva->x);
free(la_curva->y);
}
Me respondo a mí mismo. Sí se puede hacer así, lo he probado y ha
pasado de usar el 54.7% de la memoria al 7.1%, que respecto de 256MB,
sigue siendo mucho (18MB), pero ya buscaré dónde reservo memoria en
otras partes.

En cualquier caso, la función sería algo como:

void free_curva struct vector_float *la_curva)
{
free(la curva->x);
free(la_curva->y);
free(la_curva);
}

Gracias a todos.

Un Saludo
- --
Han Solo
The Rebel Alliance

Emacs is not on every system

So what? [...] Do you tell your administrative people to stick with
notepad.exe? Do you tell your fat kids they can only have the crummy
games that come with their video games or plain dress that comes with
Barbie?
Fernando Arbeiza
2003-08-14 15:56:00 UTC
Permalink
Post by Han Solo
Me respondo a mí mismo. Sí se puede hacer así, lo he probado y ha
pasado de usar el 54.7% de la memoria al 7.1%, que respecto de 256MB,
sigue siendo mucho (18MB), pero ya buscaré dónde reservo memoria en
otras partes.
Bien, pero ten en cuenta que aunque en el programa hagas un free, el
sistema operativo puede que no libere la memoria (quizá piense que el
programa puede necesitarlo antes o después). Así que no esperes que eso
que has observado pase cada vez que liberes memoria.
Post by Han Solo
void free_curva struct vector_float *la_curva)
{
free(la curva->x);
free(la_curva->y);
free(la_curva);
}
Eso es, ¿a qué no era tan horrible como tú decías ;-)?

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
J
2003-08-15 02:09:19 UTC
Permalink
Los "free" si liberan toda la memoria de todos los tipos que contengan las
estructuras, piensa que las estructuras se utilizan para "encapsular"
elementos de forma que todo esté más estructurado (valga la redundancia) y
para asegurar que todos los elementos ocuparán posiciones de memoria
contiguas.
Se me olvidó poner una cosa de la página man de "free":

"free() libera el espacio de memoria apuntado por ptr, que debe haber sido
devuelto por una llamada previa a malloc(), calloc() o realloc().
En caso contrario, o si free(ptr) ya se ha llamado antes, se produce un
comportamiento indefinido. Si ptr es NULL, no se realiza ninguna
operación."

Con lo que nos viene a decir que libera la zona de memoria apuntada por
"ptr", la cual ha sido previamente reservada mediante una de las funciones
anteriores, si la reserva se ha realizado correctamente y hemos reservado
por ejemplo, 1024 Bytes, en la operación de liberación ésta debería ser la
cantidad liberada (otra cosa es que todo se realice de forma "atómica" y
en el mismo instante de la llamada a la función, eso ya depende de la
gestión de memoria que realice el sistema operativo...

Nos vemos...
Fernando Arbeiza
2003-08-15 08:20:50 UTC
Permalink
Los "free" si liberan toda la memoria de todos los tipos que contengan las
estructuras, piensa que las estructuras se utilizan para "encapsular"
elementos de forma que todo esté más estructurado (valga la redundancia) y
para asegurar que todos los elementos ocuparán posiciones de memoria
contiguas.
Free liberará la memoria ocupada por la estructura, es decir, liberará
la memoria ocupada por los punteros; pero no la memoria a la que apuntan
esos punteros, con la que también hay que utilizar free. Quizá te ha
confundido que se hablaba de arrays, sin embargo las estructuras no
contienen arrays, sino punteros a zonas de memoria reservadas
dinámicamente.
Post by Han Solo
struct vector_float *inicia_vector(int n)
{
int i;
float *p;
struct vector_float *resultado;
resultado=(struct vector_float *)malloc(sizeof(*resultado));
p=(float *)malloc(n*sizeof(*p));
for (i=0;i<n;i++){
&p[i]=i/13; //por ejemplo,para que salga un float
^^^^
Un pequeño comentario, un int dividido entre un int te da como resultado
otro int (que luego se convertirá a float). Si quieres un float, tienes
que hacer:

&p[i]=i/13.0F;

Ah, por cierto, comprueba el valor que devuelve malloc, que te puedes
llevar sorpresas.
Creo que la asignación de memoria por medio de "malloc" no es del todo
correcta... veamos... para "resultado" estás reservando exclusivamente 4
Bytes (el tamaño de un puntero suponiendo que utilices x86) y sin embargo
para "p" (que está dentro de "resultado") reservas n*4 Bytes, con lo que
con un vector de, al menos, un elemento en el mejor de los casos con n=1
- 4 Bytes de "nelems" (un int)
- 1*4 Bytes para "f"
Total: 8 Bytes, como la estructura sólo admite 4 Bytes te debería pegar un
"punterazo" del copón... ¿no?
No, ten cuidado con esta cosas que son más sencillas de lo que parecen.
La estructura sólo contiene el puntero que apunta a la zona de memoria
que se ha reservado (es decir, _NO_ contiene los datos en sí, sino algo
que apunta a ellos).

Veamos, la estructura es esta:

struct vector_float {
int nelems;
float *f;
};

A ver si consigo dibujar el contenido de una variable vector_float y el
vector. Sería algo así:

vector_float
+--------+
| nelems | memoria reservada para el vector
+--------+ +-------------------+
| f | -------------------> | *f |
+--------+ +-------------------+
| *(f + 1) |
+-------------------+
| *(f + 2) |
+-------------------+
| |
. .
. .
| |
+-------------------+
| *(f + nelems - 1) |
+-------------------+

Es decir, que una variable vector float sólo ocupará
sizeof (int) + sizeof (float *) [1]. Lo que ocupa
nelems * sizeof (float *) es la memoria reservada para almacenar los
números.

[1] No estoy contando bytes de relleno, que puede haberlo.
En las demás funciones creo que te ocurre lo mismo, yo reservaría de la
resultado=(struct vector_float*)malloc(sizeof(int)+n*sizeof(float));
p=(float*)malloc(n*sizeof(float));
Bueno, creo que con lo anterior queda claro que esto no es como debe
hacerse. Tienes que hacerlo así:

resultado = malloc(sizeof (*resultado));
resultado->f = malloc(n * sizeof (*resultado->f));

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
J
2003-08-15 15:37:46 UTC
Permalink
Post by Fernando Arbeiza
Es decir, que una variable vector float sólo ocupará
sizeof (int) + sizeof (float *) [1]. Lo que ocupa
nelems * sizeof (float *) es la memoria reservada para almacenar los
números.
[1] No estoy contando bytes de relleno, que puede haberlo.
resultado = malloc(sizeof (*resultado));
resultado->f = malloc(n * sizeof (*resultado->f));
Un saludo.
Ahh!! se me fue la pinza por completo, hace mucho que no programo en C y
metí la pata hasta el fondo... de esta forma es cierto que que free() no
liberará toda la memoria ya que no habremos reservado todo el espacio para
"resultado"...
De todas formas la expresión:
resultado->f = malloc(n * sizeof (*resultado->f));
es igual que...
resultado->f=(float*)malloc(n*sizeof(float));
ya que sizeof(*resultado->f)=sizeof(float), mi confusión fue con el tamaño
de la estructura...

Gracias por la aclaración (así da gusto equivocarse ;-)
Fernando Arbeiza
2003-08-15 18:46:21 UTC
Permalink
Post by Fernando Arbeiza
resultado->f = malloc(n * sizeof (*resultado->f));
es igual que...
resultado->f=(float*)malloc(n*sizeof(float));
ya que sizeof(*resultado->f)=sizeof(float), mi confusión fue con el tamaño
de la estructura...
Sí, son lo mismo, pero tengo mis razones para preferir la primera.

El cast de float no es necesario porque malloc devuelve un puntero a
void que no necesita un cast para convertirse a cualquier tipo de
puntero. El cast lo único que puede hacer es enmascarar un error si no
incluyes stdlib.h.

Y, si utilizas float en lugar de utilizar la variable (*resultado->f),
si en algún momento decides cambiar el tipo de resultado->f (por un
double, por ejemplo), no tienes que andar buscando donde estaba el
malloc para cambiar el tipo de datos (además de que se te puede olvidar
cambiarlo, con el problema que acarrearía).

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
J
2003-08-15 15:46:21 UTC
Permalink
Post by Fernando Arbeiza
Post by Han Solo
struct vector_float *inicia_vector(int n)
{
int i;
float *p;
struct vector_float *resultado;
resultado=(struct vector_float *)malloc(sizeof(*resultado));
p=(float *)malloc(n*sizeof(*p));
for (i=0;i<n;i++){
&p[i]=i/13; //por ejemplo,para que salga un float
^^^^
Un pequeño comentario, un int dividido entre un int te da como resultado
otro int (que luego se convertirá a float). Si quieres un float, tienes
&p[i]=i/13.0F;
¿En esa operación no tendríamos un error de compilación?
¿No debería ser p[i]=i/13.0F o p[i]=(float)i/13?

Nos vemos...
Fernando Arbeiza
2003-08-15 19:04:00 UTC
Permalink
Post by J
Post by Fernando Arbeiza
&p[i]=i/13.0F;
¿En esa operación no tendríamos un error de compilación?
¿No debería ser p[i]=i/13.0F o p[i]=(float)i/13?
Calla, calla, es que cuando estoy con algo, me obceco y no veo nada más.
Tienes toda la razón.

Un saludo.
--
Fernando Arbeiza <URL: mailto:***@ono.com>
Crea tu propio Linux: <URL: http://www.escomposlinux.org/lfs-es>
Pascal Bourguignon
2003-08-16 10:45:28 UTC
Permalink
Post by Han Solo
Tengo un programa lleno de lindezas como estas, de estructuras
anidadas, y que van generando miles de estructuras como curva a lo
largo de la ejecución. El problema es que creo que el free no hace
nada. Sospecho que tendría que ir liberando hasta los 'arrays' de
'floats' que son los que finalmente ocupan la memoria, Pero tampoco
estoy seguro de esto.
Me gustaría saber si hay una manera de liberar todo de golpe; no me
aptece nada ponerme a hacer las funciones de limpieza...
Podrias usar un garbage collector que haria todo el trabajo
automaticamente por ti.

http://www.hpl.hp.com/personal/Hans_Boehm/gc/
--
__Pascal_Bourguignon__ http://www.informatimago.com/
----------------------------------------------------------------------
Do not adjust your mind, there is a fault in reality.
Loading...