Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 22-12-2010
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: May 2005
Ubicación: Málaga
Posts: 135
Poder: 14
Bauhaus1975 Va por buen camino
Thumbs down Problema liberando memoria: punteros y matrices

Muy buenas de nuevo.

Resulta que tengo una sección de código que me está dando quebraderos de cabeza pues al ejecutarse me da un 'out of memory'.

Voy a poner de manera resumida el código que afecta. Se trata de un proceso que para realizar cálculos estadísticos genera varios millones de elementos, y ordena. Esto de manera reiterada, el problema es que en cada iteración, seguramente, no sé liberar bien la memoria.

Este es el código en cuestión:

Código Delphi [-]
var
listaPunteros : puntero of TRegistro;
listaArray : array of TRegistro;
begin
for i:=o to n do
    SetLength(listaArray,0);
    Dispose(listaPunteros);
    listaPunteros := nil;
    listaPunteros := generaLista(); // 10 millones de elementos aprox. son devueltos
    ordenarLista_QuickSort(listaPunteros);
    // Aqui pasamos al array que nos sirve luego para otras partes del proyecto.
    listaArray:= lista2Array(listaPunteros);
{
[..] A partir de aqui se hacen unos cálculos (en listaArray) para evaluar unos valores estadisticos,
 y vuelta a empezar en el bucle principal.
>> Al realizar 5 iteraciones ya está el sistema 'petado'
}
end;
Bien, el por qué de hacerlo así con punteros de manera intermedia, es porque los tiempos de ejecución de este proceso en particular son muy diferentes a trabajar unicamente con arrays.

¿Podéis echarme una mano?
Gracias y un saludo.

Última edición por rgstuamigo fecha: 22-12-2010 a las 23:13:53. Razón: Estética en el código
Responder Con Cita
  #2  
Antiguo 22-12-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: Sep 2004
Ubicación: En algún lugar.
Posts: 28.246
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Falta más código para poder echarle un vistazo
Responder Con Cita
  #3  
Antiguo 22-12-2010
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: May 2005
Ubicación: Málaga
Posts: 135
Poder: 14
Bauhaus1975 Va por buen camino
Hola Casimiro,

Es que el código es bastante abundante, lo he resumido.
De tal modo que el problema tiene que generarse en las operaciones que se hacen al resetear la lista de punteros y el array (creo).

Si me dices que con el Dispose y el SetLength es OK para gestionar bien la memoria en cada iteración, me pongo manos a la obra a ver si puedo poner más completo el código.

Gracias y un saludo.
Responder Con Cita
  #4  
Antiguo 22-12-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: Sep 2004
Ubicación: En algún lugar.
Posts: 28.246
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Es que así es casi imposible poder ayudarte, por ejemplo:
SetLength(listaArray,0); ¿cero?, entonces no ingresarás nada aquí, supongo
for i:=o to n do ¿qué es 'o' y 'n'?
listaPunteros := generaLista(); ni idea de lo que hace esa función
etc.

O sea, ni idea de por dónde ayudarte
Responder Con Cita
  #5  
Antiguo 22-12-2010
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: May 2005
Ubicación: Málaga
Posts: 135
Poder: 14
Bauhaus1975 Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Es que así es casi imposible poder ayudarte
OK (Gracias por la ayuda). Voy a responderte a algunas de tus dudas e intentaré ponerlo más claro, pero ya verás que al ahorrarme poner todo el codigo lo que hago es simplificar la exposición.

Cita:
Empezado por Casimiro Notevi Ver Mensaje
SetLength(listaArray,0); ¿cero?, entonces no ingresarás nada aquí,
Sí, si se insertan datos. En la llamada a lista2Array se pasan los nodos de lalista de punteros a listaArray (pasar listaPunteros a Array) -> Al final del blucle.

for i:=o to n do ¿qué es 'o' y 'n'?

perdón '0' y 'n', no es relevante, simplemente el proceso se repite. en el proceso real i es un año de una lista de [añoInicio..añoFin].

listaPunteros := generaLista(T); ni idea de lo que hace esa función

etc. a partir de una tabla 'T': 3x14, cada celda tiene un valor de probabilidad 'p'. Bien pues la función genera todas las combinaciones de combinar 1 columna de las 14 filas.
Lo importante es que devuelve 3 elevado a 14 elementos enlazados en una lista de punteros con esos valores de probabilidad. Luego esa lista es ordenada, para tener toda la lista de valores de probabilidad ordenados de mayor a menor, por último se pasa de la lista de punteros a array (con la susodicha función lista2Array()).

No sé si comentar el código mucho mejor... pero creo que poniendo todo el tocho, al ser un tema de cálculo, va a ser más dificil de entender.
La clave está en ver como liberar la memoria en la lista de punteros y array en cada iteración... Que me da la sensación que aunque haga el 'Dispose' a la lista de punteros, el recolector de memoria o gestor no hace uso de la memoria (no sé hasta cuando)..

Saludos.

Última edición por Bauhaus1975 fecha: 22-12-2010 a las 19:04:47.
Responder Con Cita
  #6  
Antiguo 22-12-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: Sep 2004
Ubicación: En algún lugar.
Posts: 28.246
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Entonces se supone que redimensionas listaArray en otro sitio, no?
SetLength(listaArray,0);
Responder Con Cita
  #7  
Antiguo 22-12-2010
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: May 2005
Ubicación: Málaga
Posts: 135
Poder: 14
Bauhaus1975 Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Entonces se supone que redimensionas listaArray en otro sitio, no?
SetLength(listaArray,0);
Claro, en la llamada:
Código Delphi [-]
// Aqui pasamos a listaArray los elementos de la lista de nodos.
listaArray:= lista2Array(listaPunteros);
se recorre la lista de punteros y se van añadiendo, en ese proceso va creciendo, y por tanto redimensionándose.
Luego a comienzo de la siguiente iteración hay que resetear las listas, tanto listaArray como listaPunteros.

Código Delphi [-]
SetLength(listaArray,0);
Dispose(listaPunteros);
listaPunteros := nil;
[.. etc ..]
Responder Con Cita
  #8  
Antiguo 22-12-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: Sep 2004
Ubicación: En algún lugar.
Posts: 28.246
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Y si sabes cuántos valores vas a poner en el array, ¿por qué no lo haces de primera hora?, ejemplo: SetLength(listaArray,16384); y luego liberas la memoria.
No sé cómo lo hace delphi en estos casos, pero si tienes un array de n elementos y lo vas a redimensionar... puede que simplemente lo aumente de tamaño o puede ser que cree uno nuevo con el nuevo tamaño, pase los valores del viejo al nuevo, borre el viejo y ya tienes todo en el nuevo.
En este último caso todo el proceso será mucho más lento que en el primer caso y necesitarás el doble de memoria, que lo enlentecerá mucho más todavía.
Responder Con Cita
  #9  
Antiguo 22-12-2010
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: May 2005
Ubicación: Málaga
Posts: 135
Poder: 14
Bauhaus1975 Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Y si sabes cuántos valores vas a poner en el array, ¿por qué no lo haces de primera hora?, ejemplo: SetLength(listaArray,16384); y luego liberas la memoria.
No sé cómo lo hace delphi en estos casos, pero si tienes un array de n elementos y lo vas a redimensionar... puede que simplemente lo aumente de tamaño o puede ser que cree uno nuevo con el nuevo tamaño, pase los valores del viejo al nuevo, borre el viejo y ya tienes todo en el nuevo.
En este último caso todo el proceso será mucho más lento que en el primer caso y necesitarás el doble de memoria, que lo enlentecerá mucho más todavía.
Una simple propuesta la tuya, que puede ser parte de la solución (cuánto cuesta a veces simplificar). Realmente conozco a priori la longitud de las listas, esto es 3 elevado a |T|.
Así que voy a tratar de definir una vez la longitud, y revisar el uso de la lista de Arrays. Por otra parte voy a implementar una función para recorrer la lista de punteros y liberar uno a uno los nodos, pues he leido que de no ser así no voy a estar haciendo bien las cosas.

Cuando haya probado estos cambios os cuento como fue.
Gracias de nuevo y un saludo.
Responder Con Cita
  #10  
Antiguo 22-12-2010
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 19
Delphius Va camino a la fama
Hola,

Disculpen que me meta pero va a ser necesario bajar más a tierra las cosas que expones. Si nos describes al menos la parte en que asignas y liberas memoria y la definición de los tipos podríamos ver en donde está la falla. De otro modo estaríamos adivinando en que parte de todo tu código que te resignas a mostrar está el error.

Lo que en todo caso deberías hacer es realizar un seguimiento o traza a tu código añadiendo breakpoints y evaluando paso a paso como se comporta hasta hallar el problema. O en todo caso deja al sistema que se ejecute hasta encontrar el error y la línea. Ya con eso se puede saber más o menos donde estaría el problema. Esa es la UNICA manera de saber donde está el problema.

Por otro lado ¿Porqué utilizar lista de punteros a la vieja escuela? ¿Es un requisito u obligación? Porque Delphi ya cuenta con clases que cumplen perfectamente con las funciones de listas... entre ellas la clase TList.

Con ello te evitas cualquier problema de liberación y asignación... la clase ya cuenta con los métodos necesarios, solo debes hacer uso de la clase.

Ahora, la segunda pregunta, ¿Qué sentido tiene hacer una conversión de lista a un array? ¿Porqué no directamente operar sobre el array?

Aviso que trabajar con arrays dinámicos como este:

Código Delphi [-]
type
TArray = array of integer;

Tiene sus inconvenientes. Por empezar, cuando uno redimensiona con SetLength() lo que hace es copiar el array en un zona temporal, redimensionar y volver a volcar el contenido del array temporal.

Por tanto cuanto más grande sea el array más lento será el acceso a memoria.

En lo posible debe evitarse estar redimensionando los arrays, en todo caso se puede ganar algo de eficiencia volcando los contenidos en un array auxiliar del tamaño indicado y luego al finalizar o a medida que los cálculos se van ejecutando ir liberando memoria.

Si bien internamente SetLength() trabaja con llamadas a GetMem y FreeMem, si se está trabajando con arreglos muy grandes es mejor trabajar directamente con GetMem y FreeMem y reservar un espacio de memoria y operarla como si se tratase de un arreglo. Se gana más, aunque es un poco más lioso en términos de código.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #11  
Antiguo 24-12-2010
Bauhaus1975 Bauhaus1975 is offline
Miembro
 
Registrado: May 2005
Ubicación: Málaga
Posts: 135
Poder: 14
Bauhaus1975 Va por buen camino
Muy buenas de nuevo

He conseguido mejorar mucho la ejecución de mi programa. De tal manera que con las pautas que habiamos fijado, la gráfica de memoria se comporta como debería: Sube y baja sin pasar de un nivel 'apropiado'.
Sin duda, liberar correctamente la lista, evitar redimensionar las matrices con 'Setlength' etc han conseguido esto.

Cita:
Empezado por Delphius Ver Mensaje
Hola,
Disculpen que me meta pero va a ser necesario bajar más a tierra las cosas que expones. Si nos describes al menos la parte en que asignas y liberas memoria y la definición de los tipos podríamos ver en donde está la falla. De otro modo estaríamos adivinando en que parte de todo tu código que te resignas a mostrar está el error.

Lo que en todo caso deberías hacer es realizar un seguimiento o traza a tu código añadiendo breakpoints y evaluando paso a paso como se comporta hasta hallar el problema. O en todo caso deja al sistema que se ejecute hasta encontrar el error y la línea. Ya con eso se puede saber más o menos donde estaría el problema. Esa es la UNICA manera de saber donde está el problema.
No es ninguna intromisión pues con la ayuda de todos se consigue avanzar.
El problema es que en el segmento de código que expuse, se hace referencia a mil funciones que tendría que poner, que entiendo no afectan a la asignación / liberación de memoria.

He trabajado depurando pormenorizadamente, así he podido mejorar la situación. En fin, error no había, simplemente que con listas grandes hay que trabajar todo con cuidado.

Cita:
Empezado por Delphius Ver Mensaje
Por otro lado ¿Porqué utilizar lista de punteros a la vieja escuela? ¿Es un requisito u obligación? Porque Delphi ya cuenta con clases que cumplen perfectamente con las funciones de listas... entre ellas la clase TList.

Con ello te evitas cualquier problema de liberación y asignación... la clase ya cuenta con los métodos necesarios, solo debes hacer uso de la clase.
Utilizo lista de punteros porque este proyecto es mi proyecto de fin de carrera, con el que llevo a cuestas muchos años ya y tiene herencias de un pasado donde tenía menos conocimiento (incluso ) que ahora. Además, por causas del tutor sus requerimientos han variado mucho en los últimos tiempos. (No tienen mas que revisar mis posts para ver que de vez en cuando vuelvo a la carga con cuestiones para este proyecto)

Cita:
Empezado por Delphius Ver Mensaje
Ahora, la segunda pregunta, ¿Qué sentido tiene hacer una conversión de lista a un array? ¿Porqué no directamente operar sobre el array?

Aviso que trabajar con arrays dinámicos como este:


Código Delphi [-]type
TArray = array of integer;




Tiene sus inconvenientes. Por empezar, cuando uno redimensiona con SetLength() lo que hace es copiar el array en un zona temporal, redimensionar y volver a volcar el contenido del array temporal.

Por tanto cuanto más grande sea el array más lento será el acceso a memoria.
Cuando empecé a trabajar las listas de elementos y ordenación, por tiempos de ejecución tuve que hacer esas operaciones sobre listas de punteros, estando el resto de menciones en el proyecto usando arrays. Así que así ha quedado...

He tomado buena nota de tus explicaciones para trabajar con arrays grandes. Gracias por los consejos que espero poner en práctica.

Ahora me he dado cuenta de que tendría que mejorar muchas partes del código que tengo... pero espero que de momento aguante todo, a ver si puedo finalizar ya este tema.

Gracias de nuevo a todos y un saludo.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Problema con punteros waremovil C++ Builder 2 18-08-2007 18:47:19
Liberación de memoria de punteros Data de un Tree. afxe Varios 5 20-06-2007 17:12:34
Memoria virtual para grandes matrices JF Sebastian OOP 2 30-01-2007 20:11:41
Problema con matrices que no logro resolver galmacland Varios 11 20-06-2006 19:03:45
sobre punteros... y memoria ¿Como perder su valor, sin hacerlo? Delphius Varios 8 19-04-2006 10:55:06


La franja horaria es GMT +2. Ahora son las 20:01:00.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi