Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SOLUCIONADO] Quien tiene mayor capacidad vector o list

Estas en el tema de Quien tiene mayor capacidad vector o list en el foro de C/C++ en Foros del Web. Hola amigos, Tengo un algoritmo muy grande que guarda un arreglo de vector<vector<int>> el algoritmo me fallaba (en release) cuando hacía un push_back más (luego ...
  #1 (permalink)  
Antiguo 16/02/2016, 01:45
 
Fecha de Ingreso: junio-2014
Mensajes: 144
Antigüedad: 9 años, 10 meses
Puntos: 1
Quien tiene mayor capacidad vector o list

Hola amigos,

Tengo un algoritmo muy grande que guarda un arreglo de vector<vector<int>> el algoritmo me fallaba (en release) cuando hacía un push_back más (luego de hacer muchos otros claro) y me fije que el tamaño del vector era de más de 7 millones.

Entonces verifiqué la función max_size y era mucho más grande que 7 millones, por tanto pensé que el lío era que cuando superaba su capacidad el, como es vector, debe mudarse a otro sector de la memoria donde si alcance, pero no encontraba un bloque de memoria tan grande para alcanzar.

Por tanto dije vale usaré entonces las listas list<list<int>> que al ser listas enlazadas no necesitan mudarse a otro sector pues están desperdigados los elementos por toda la memoria, cual fue mi sorpresa de que no solo fallaba enlo mismo sino que el tamaño era de 1 millón algo, mucho menos que el vector (7 millones). Eso realmente no me lo esperaba. No se supone que la lista debería poder almacenar mucho más según esta lógica?

saludos
  #2 (permalink)  
Antiguo 16/02/2016, 03:13
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Quien tiene mayor capacidad vector o list

vector

La clase vector almacena todos los datos de forma secuencial. Esta mecánica hace que cada vez que se llene tenga que hacerse un realloc a una región más grande... con la penalización de rendimiento que conlleva copiar regiones grandes de memoria. Como toda la información está contenida en una única región de memoria, para gestionar los datos únicamente hacen falta tres variables:

  • Un puntero que apunte al inicio de la región de memoria
  • Un entero que indique el número máximo de elementos
  • Un entero que indique la cantidad de posiciones ocupadas


Asumiendo que un entero y un puntero son 4 bytes, almacenar 1 millón de elementos de 4 bytes ocuparía: 1.000.000 * 4 + 3 * 4 = 4.000.012 bytes

list

La clase lista implementa una lista doblemente enlazada. En este caso añadir nuevos elementos supone un coste más o menos estable y constante de tiempo ya que no implica reallocs. La penalización de este contenedor la encontramos al acceder a un elemento aleatorio, ya que obliga a recorrer diferentes nodos para dar con el elemento en cuestión... en listas largas la penalización aumenta.

Una lista doblemente enlazada necesita dos punteros por cada elemento de la lista... uno apuntando al elemento anterior y otro al siguiente. Además necesitamos un puntero al primer nodo de la lista. Para almacenar un millón de elementos tenemos que: 3 * 4 * 1.000.000 + 4 = 12.000.004 bytes

¿De dónde sale ese 3? puntero al elemento anterior + puntero al elemento siguiente + el dato a almacenar = 3 * 4 bytes

Estos cálculos son a grandes rasgos, pero sirven para hacerse una idea de los requisitos de memoria.

¿Soluciones?

Lo más óptimo sería usar std::vector pero reservando la memoria previamente. De esta forma evitamos reallocs y nos aseguramos de disponer de la memoria necesaria para ejecutar nuestro algoritmo.

Para que el vector reserve memoria hay que llamar al método reserve(). Este método fuerza al vector a reservar memoria para almacenar, al menos la cantidad de elementos que le indiquemos.

Si no tenemos a priori ninguna certeza ni aproximación sobre cuáles van a ser los recursos de la aplicación puedes tener un problema. Piensa que al hacer reallocs el sistema operativo tiene que ser capaz de encontrar regiones de memoria cada vez más grandes...y eso puede ser un problema debido a que la memoria tiende a fragmentarse... usar listas enlazadas no es la solución debido a su mayor consumo de recursos.

Tienes una alternativa y es implementar un contenedor que gestione bloques de memoria... estaría a medio camino entre los dos contenedores de los que hablamos... la clase en cuestión reservaría la memoria en bloques de X elementos... cuando el bloque se llene reserva uno nuevo. Este diseño podría adaptarse mejor a los requisitos de tu aplicación... pero te tocaría implementarlo de 0 salvo que encuentres una implementación ya hecha.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #3 (permalink)  
Antiguo 16/02/2016, 03:56
 
Fecha de Ingreso: junio-2014
Mensajes: 144
Antigüedad: 9 años, 10 meses
Puntos: 1
Respuesta: Quien tiene mayor capacidad vector o list

Gracias, lo entiendo, pero en teoría el list puede almacenar más pues, si el vector no encuentra un bloque de memoria suficientemente grande no pude aumentar de tamaño. Pero las list pueden meterse en "huecos" en la memoria, no en bloques.

He hecho esta prueba, uso visualStudio 2013 por eso el tamaño del int es de 2147483647.

Código C++:
Ver original
  1. #include <iostream>
  2. #include <vector>
  3. #include <list>
  4.  
  5. using namespace std;
  6.  
  7.  
  8. int main(){
  9.     int i,j;
  10.    
  11.     vector<int> vAux;
  12.     for (i = 0; i < 50; i++)vAux.push_back(i);
  13.     list<int> lAux;
  14.     for (i = 0; i < 50; i++)lAux.push_back(i);
  15.     i = 0;
  16.     j = 111222000;  //max 2147483647;
  17.     vector<vector<int>> v;
  18.     cout << "max size: " << v.max_size() << endl;
  19.     cout << "j.......: " << j << endl;
  20.     cout << "i.......: " << i << endl;
  21.  
  22.     for (i = 0; i < j; i++){
  23.         v.push_back(vAux);
  24.         if (i % 500000 == 0) cout << " i: " << i << endl;
  25.         if (i > 7500000 && i % 100000==0) cout << " ii: " << v.size() << endl;
  26.     }
  27.     cout << i << endl;
  28.  
  29.     cin.sync();
  30.     cin.get();
  31.     return 0;
  32. }

Y es muy raro, el maxi size (tengo 16 gigas de ram) es de 357.913.941 y el código falla cuando el vector tiene poco más de 7.900.000.

Otra cosa que no entiendo bien es porqué este resultado se altera si lo corro en debug, es decir falla a los 5 millones en debug no a los 7 millones como en release.

El problema no es que falte memoria creo, sino que el vector no aumenta más a pesar de que está dentro de sus capacidades.

Haciendo lo que me recomendó eferion hice esta prueba:

Código C++:
Ver original
  1. int main(){
  2.     int i, j;
  3.  
  4.     vector<int> vAux;
  5.     for (i = 0; i < 50; i++)vAux.push_back(i);
  6.     list<int> lAux;
  7.     for (i = 0; i < 50; i++)lAux.push_back(i);
  8.     i = 0;
  9.     j = 111222000;  //max 2147483647;
  10.     vector<vector<int>> v;
  11.     cout << "max size: " << v.max_size() << endl;
  12.     cout << "j.......: " << j << endl;
  13.     cout << "i.......: " << i << endl;
  14.     v.reserve(j);
  15.     for (i = 0; i < j; i++){
  16.         v.push_back(vAux);
  17.         if (i % 500000 == 0) cout << " i: " << i << endl;
  18.         if (i > 7500000 && i % 100000 == 0) cout << " ii: " << v.size() << endl;
  19.     }
  20.     cout << i << endl;
  21.  
  22.     cin.sync();
  23.     cin.get();
  24.     return 0;
  25. }

Y el problema es que el vector es lo suficientemente grande pero para mi sorpresa da el mismo error de bad_alloc at memory location a pocos más de 3.500.000 menos que antes.

Qué es lo que pasa, no tiene sentido. En todo esto el proceso sólo usa casi 2 gb de memoria ram, y mi windows usa más o menos 4 para un total de 6 de mis 16gb. No creo que el problema sea de memoria.

Saludos,

Última edición por dmorill; 16/02/2016 a las 04:16 Razón: Más información.
  #4 (permalink)  
Antiguo 16/02/2016, 06:23
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Quien tiene mayor capacidad vector o list

Cita:
Iniciado por dmorill Ver Mensaje
Gracias, lo entiendo, pero en teoría el list puede almacenar más pues, si el vector no encuentra un bloque de memoria suficientemente grande no pude aumentar de tamaño. Pero las list pueden meterse en "huecos" en la memoria, no en bloques.
Sí, pero cada elemento de un list ocupa más que un elemento de vector... luego el consumo de memoria de un list siempre va a ser superior....

Cita:
Iniciado por dmorill Ver Mensaje
He hecho esta prueba, uso visualStudio 2013 por eso el tamaño del int es de 2147483647.
Ya lo he comentado otras veces... usar los tipos nativos de C++ empieza a considerarse una práctica obsoleta por lo variable del rango de valores. La librería stdint tiene disponibles tipos de tamaño fijo independiente de la plataforma, lo cual garantiza un rango de valores fijo... algo extremadamente importane en muchísimos algoritmos.

Por cierto, como complemento a stdint, tienes a tu disposición inttypes, que te proporciona macros útiles para imprimir variables de rango fijo independientemente de la plataforma utilizada.

Cita:
Iniciado por dmorill Ver Mensaje
Y es muy raro, el maxi size (tengo 16 gigas de ram) es de 357.913.941 y el código falla cuando el vector tiene poco más de 7.900.000.
¿Por qué es raro? Estás creando un vector de vectores. Estás creando 7.900.000 vectores y en cada vector almacenas 50 elementos. Si haces un sizeof de vector en mi caso da 12 bytes. A esto tienes que añadir la información RTTI que acompaña por defecto a cada clase de C++ (lo que permite que funcione dynamic_cast entre otras cosas y que no sale con sizeof, por lo que no se tendrá en cuenta en los cálculos pero que sepas que también está)

Con todo esto el consumo aproximado de memoria es:

Por cada vector: 12 + 50 * 4 = 212
En total: 7.900.000 * 212 = 1.674.800.000 bytes = 1.56 GB... como puedes ver el consumo no es despreciable. A eso tienes que añadirle que cuando v hace un realloc fuerza un realloc en cascada de todos los vectores almacenados en v, luego el consumo de memoria implicado en el realloc es considerable. Piensa que detrás de una simple acción puede desatarse una cadena de acontecimientos castastrófica.

Cita:
Iniciado por dmorill Ver Mensaje
Otra cosa que no entiendo bien es porqué este resultado se altera si lo corro en debug, es decir falla a los 5 millones en debug no a los 7 millones como en release.
Esto es porque en debug se añaden marcas que facilitan la depuración del código... y esas marcas tienen la mala costumbre de ocupar recursos.

Cita:
Iniciado por dmorill Ver Mensaje
El problema no es que falte memoria creo, sino que el vector no aumenta más a pesar de que está dentro de sus capacidades.
Cita:
Iniciado por dmorill Ver Mensaje
Haciendo lo que me recomendó eferion hice esta prueba...
Y "sorprendentemente" falla antes. Lo único que has hecho con eso es que el vector principal acapare más memoria... más memoria consumida por el vector principal = menos cantidad de vectores secundarios... ¿sigues pensando que no es un problema de memoria?

La memoria tiende a fragmentarse... esto es, empieza a tener huecos. Cuanto más uso se le da a un equipo más fragmentada suele estar. Si resulta que el sistema operativo no es capaz de encontrar un hueco lo suficientemente grande como para ubicar la cantidad de memoria que se le pide, el proceso simplemente falla. Si tienes 16 GB de memoria bastan 15 bytes ocupando puntos estratégicos para que tu sistema operativo no sea capaz de reservar paquetes superiores a 1GB
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.

Última edición por eferion; 16/02/2016 a las 06:34
  #5 (permalink)  
Antiguo 16/02/2016, 07:25
 
Fecha de Ingreso: junio-2014
Mensajes: 144
Antigüedad: 9 años, 10 meses
Puntos: 1
Respuesta: Quien tiene mayor capacidad vector o list

Cita:
Iniciado por eferion Ver Mensaje
Y "sorprendentemente" falla antes. Lo único que has hecho con eso es que el vector principal acapare más memoria... más memoria consumida por el vector principal = menos cantidad de vectores secundarios... ¿sigues pensando que no es un problema de memoria?

La memoria tiende a fragmentarse... esto es, empieza a tener huecos. Cuanto más uso se le da a un equipo más fragmentada suele estar. Si resulta que el sistema operativo no es capaz de encontrar un hueco lo suficientemente grande como para ubicar la cantidad de memoria que se le pide, el proceso simplemente falla. Si tienes 16 GB de memoria bastan 15 bytes ocupando puntos estratégicos para que tu sistema operativo no sea capaz de reservar paquetes superiores a 1GB
Hola, según ésto si lo hago con listas (aunque ocupe más por elemento) debería poder llenar la lista hasta la capacidad de la ram, cierto? lo probé con el código de antes cambiándolo a list<list<int>> v;.

Código C++:
Ver original
  1. int main(){
  2.     int i,j;
  3.    
  4.     vector<int> vAux;
  5.     for (i = 0; i < 50; i++)vAux.push_back(i);
  6.     list<int> lAux;
  7.     for (i = 0; i < 50; i++)lAux.push_back(i);
  8.     i = 0;
  9.     j = 111222000;  //max 2147483647;
  10.     list<list<int>> v;
  11.     cout << "max size: " << v.max_size() << endl;
  12.     cout << "j.......: " << j << endl;
  13.     cout << "i.......: " << i << endl;
  14.  
  15.     for (i = 0; i < j; i++){
  16.         v.push_back(lAux);
  17.         if (i % 500000 == 0) cout << " i: " << i << endl;
  18.         //if (i > 7500000 && i % 100000==0) cout << " ii: " << v.size() << endl;
  19.     }
  20.     cout << "Presione cualquier tecla para salir..." << endl;
  21.  
  22.     cin.sync();
  23.     cin.get();
  24.     return 0;
  25. }

Y si falló antes, lo que concuerda con lo que dices acerca de que usa más memoria, pero parece que los dos llegan a un "tope" o limite, y en el vector la respuesta es la que tu me dices, que la memoria se fragmenta y se llena de huecos, pero con el caso de las listas, porqué ocurre? ellas no necesitan bloques grandes de memoria.

Saludos,
  #6 (permalink)  
Antiguo 16/02/2016, 07:36
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 6 meses
Puntos: 204
Respuesta: Quien tiene mayor capacidad vector o list

Estás compilando la aplicación en modo 32 bits o 64???

32 bits limita la redirección a 2GB...
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #7 (permalink)  
Antiguo 16/02/2016, 08:41
Avatar de xKuZz  
Fecha de Ingreso: febrero-2015
Ubicación: nullptr
Mensajes: 183
Antigüedad: 9 años, 2 meses
Puntos: 27
Respuesta: Quien tiene mayor capacidad vector o list

Varias aclaraciones extra:
1) max_size() te devuelve una supuesta capacidad máxima teórica basada en las especificaciones del sistema, lo único que puedes estar seguro es que si se alcanza ese número de elementos ese va a ser el máximo, pero lo normal es que mucho antes de alcanzarlos se produzca la excepción por falta de memoria, puesto que max_size no sabe los procesos que hay activos en el SO etc.

2) La memoria virtual está paginada (esto en realidad es un poco más complejo pero para que te hagas a la idea) si una página direcciona pongamos 1 KB de RAM y un proceso necesita 10 bytes de RAM al proceso se le asigna la página entera y los 1014 bytes restantes quedan desperdiciados. Esto ocurre si dicho proceso no puede ser retirado de memoria principal porque es un proceso del núcleo que no puede ser retirado o algo del estilo. Esta paginación es una de las cosas que producen la fragmentación.

3) Como te ha dicho eferion si trabajas con 32 bits el límite de ram disponible queda reducido considerablemente y si no me equivoco creo que son 2^32 direcciones = 4 GB
  #8 (permalink)  
Antiguo 18/02/2016, 05:38
 
Fecha de Ingreso: junio-2014
Mensajes: 144
Antigüedad: 9 años, 10 meses
Puntos: 1
Respuesta: Quien tiene mayor capacidad vector o list

Hola amigos, gracias de nuevo por su ayuda. En efecto la cuestión fue que estaba compilando en 32 bits, con 64 ya me funciona hasta que se llena mi memoria ram jeje

Etiquetas: list, vector
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:03.