programacion - pilas en c++ ejercicios resueltos
¿Por qué el tamaño de la memoria de pila es tan limitado? (7)
Cuando asigna memoria en el montón, el único límite es la memoria RAM libre (o memoria virtual). Hace Gb de memoria.
Entonces, ¿por qué el tamaño de la pila es tan limitado (alrededor de 1 Mb)? ¿Qué razón técnica te impide crear objetos realmente grandes en la pila?
Actualización : Mi intención puede no ser clara, no quiero asignar objetos grandes en la pila y no necesito una pila más grande. Esta pregunta es pura curiosidad.
Es solo un tamaño predeterminado. Si necesita más, puede obtener más, generalmente diciéndole al vinculador que asigne espacio extra a la pila.
La desventaja de tener pilas grandes es que si creas muchos hilos, necesitarán una pila cada uno. Si todas las pilas están asignando MB múltiples, pero no lo usan, el espacio se desperdiciará.
Debes encontrar el equilibrio adecuado para tu programa.
Algunas personas, como @BJovke, creen que la memoria virtual es esencialmente gratuita. Es cierto que no necesita tener memoria física que respalde toda la memoria virtual. Tienes que ser capaz de al menos dar direcciones a la memoria virtual.
Sin embargo, en una PC típica de 32 bits, el tamaño de la memoria virtual es el mismo que el de la memoria física, porque solo tenemos 32 bits para cualquier dirección, virtual o no.
Como todos los hilos en un proceso comparten el mismo espacio de direcciones, tienen que dividirlo entre ellos. Y después de que el sistema operativo haya tomado su parte, queda "solo" 2-3 GB para una aplicación. Y ese tamaño es el límite tanto para la memoria física como para la virtual, porque simplemente no hay más direcciones.
Mi intuición es la siguiente. La pila no es tan fácil de administrar como el montón. La pila debe almacenarse en ubicaciones de memoria continua. Esto significa que no puede asignar aleatoriamente la pila según sea necesario, pero necesita al menos reservar direcciones virtuales para ese fin. Cuanto mayor sea el tamaño del espacio de direcciones virtuales reservadas, menos hilos se pueden crear.
Por ejemplo, una aplicación de 32 bits generalmente tiene un espacio de direcciones virtuales de 2 GB. Esto significa que si el tamaño de la pila es de 2MB (por defecto en pthreads), entonces puede crear un máximo de 1024 hilos. Esto puede ser pequeño para aplicaciones como servidores web. Aumentando el tamaño de la pila a, digamos, 100MB (es decir, reserva 100MB, pero no necesariamente asigna 100MB a la pila inmediatamente), limitaría el número de subprocesos a aproximadamente 20, lo que puede ser limitante incluso para aplicaciones GUI simples.
Una pregunta interesante es, ¿por qué todavía tenemos este límite en plataformas de 64 bits? No sé la respuesta, pero supongo que la gente ya está acostumbrada a algunas "mejores prácticas de acumulación": tenga cuidado de asignar grandes objetos en el montón y, si es necesario, aumentar manualmente el tamaño de la pila. Por lo tanto, a nadie le resultó útil agregar soporte de pila "enorme" en plataformas de 64 bits.
Muchas de las cosas para las que crees que necesitas una gran pila, se pueden hacer de otra forma.
Los "Algoritmos" de Sedgewick tienen un par de buenos ejemplos de "eliminar" la recursión de algoritmos recursivos como QuickSort, al reemplazar la recursión con iteración. En realidad, el algoritmo sigue siendo recursivo, y todavía existe como pila, pero usted asigna la pila de clasificación en el montón, en lugar de usar la pila de tiempo de ejecución.
(Estoy a favor de la segunda edición, con algoritmos dados en Pascal. Se puede haber usado por ocho dólares).
Otra forma de verlo es que si crees que necesitas una gran pila, tu código es ineficiente. Hay una forma mejor de usar menos stack.
Piense en la pila en el orden de casi muy lejos. Los registros están cerca de la CPU (rápido), la pila está un poco más lejos (pero todavía está relativamente cerca) y el montón está lejos (acceso lento).
La pila vive en el montón, por supuesto, pero aún así, dado que se usa de forma continua, probablemente nunca abandone la memoria caché de la CPU, por lo que es más rápido que solo el acceso promedio al montón. Esta es una razón para mantener la pila de un tamaño razonable; para mantenerlo en la memoria caché tanto como sea posible. La asignación de objetos de gran pila (posiblemente redimensionando automáticamente la pila a medida que se producen desbordamientos) va en contra de este principio.
Entonces, es un buen paradigma para el rendimiento, no solo un residuo de los viejos tiempos.
Por un lado, la pila es continua, por lo que si asigna 12 MB, debe eliminar 12 MB cuando desee ir por debajo de lo que haya creado. También mover objetos alrededor se vuelve mucho más difícil. Aquí hay un ejemplo del mundo real que puede hacer las cosas más fáciles de entender:
Supongamos que está apilando cajas alrededor de una habitación. Cuál es más fácil de administrar:
- apilando cajas de cualquier peso una encima de la otra, pero cuando necesitas conseguir algo en el fondo tienes que deshacer todo tu montón. Si quieres sacar un objeto de la pila y dárselo a otra persona, debes quitar todas las cajas y mover la caja a la pila de la otra persona (solo pila).
- Colocas todas tus cajas (excepto las cajas realmente pequeñas) en un área especial donde no apilas cosas encima de otras cosas y anotas dónde las pones en un pedazo de papel (un puntero) y colocas el papel sobre la pila. Si necesita entregar la caja a otra persona, simplemente le entrega el papelito de su pila, o simplemente déles una fotocopia del papel y deje el original donde estaba en su pila. (Pila + montón)
Esos dos ejemplos son generalizaciones burdas y hay algunos puntos que son evidentemente incorrectos en la analogía, pero están lo suficientemente cerca como para que, con suerte, te ayuden a ver las ventajas en ambos casos.
Un aspecto que nadie ha mencionado aún:
Un tamaño de pila limitado es un mecanismo de detección y contención de errores.
En general, el trabajo principal de la pila en C y C ++ es hacer un seguimiento de la pila de llamadas y las variables locales, y si la pila crece fuera de límites, casi siempre es un error en el diseño y / o el comportamiento de la aplicación .
Si se permite que la pila crezca arbitrariamente grande, estos errores (como recursión infinita) se atraparán muy tarde, solo después de que se agoten los recursos del sistema operativo. Esto se evita estableciendo un límite arbitrario para el tamaño de la pila. El tamaño real no es tan importante, aparte de que es lo suficientemente pequeño para evitar la degradación del sistema.
No creo que haya ninguna razón técnica, pero sería una aplicación extraña que acaba de crear solo un enorme súper objeto en la pila. Los objetos de pila carecen de flexibilidad que se vuelve más problemática a medida que aumenta el tamaño: no se puede volver sin destruirlos y no se pueden poner en cola con otros hilos.