¿Cuánto uso de pila es demasiado?


22

Últimamente cuando he estado escribiendo C o C ++, declararé todas mis variables en la pila solo porque es una opción, a diferencia de Java.

Sin embargo, he oído que es una mala idea declarar cosas grandes en la pila.

  1. ¿Por qué es exactamente este el caso? Creo que el desbordamiento de la pila está involucrado, pero no tengo muy claro por qué sucede eso.
  2. ¿Cuántas cosas en la pila son demasiado?

No estoy tratando de poner archivos de 100 MB en la pila, solo una docena de matrices de kilobytes para usar como búferes de cadenas o lo que sea. ¿Es esto demasiado uso de la pila?

(Lo siento si está duplicado, la búsqueda de la pila seguía dando referencias a Stack Overflow. Ni siquiera hay una etiqueta de pila de llamadas, solo utilicé la abstracta).


1
¿Cómo se "colocan archivos de 100 MB en la pila"? Las implementaciones de búfer y contenedor (y similares como std :: string) generalmente usan el montón para almacenar su carga útil.
Murphy

2
Puede salirse con la suya con una buena cantidad de uso de pila por función / método hasta que la recursión esté involucrada, luego se arriesga a limitar severamente sus capacidades, en relación con la profundidad recursiva, por lo que dentro de las funciones recursivas, desea usar como poco local espacio variable / pila como sea posible.
Erik Eidt

3
Tenga en cuenta que C y C ++ son diferentes. Una std::vector<int>variable local no consumirá mucho espacio de pila, la mayoría de los datos están en el montón.
Basile Starynkevitch

Respuestas:


18

Depende de tu sistema operativo. En Windows, el tamaño máximo típico para una pila es de 1 MB, mientras que es de 8 MB en un Linux moderno típico, aunque esos valores son ajustables de varias maneras. Si la suma de las variables de su pila (incluida la sobrecarga de bajo nivel, como las direcciones de retorno, los argumentos basados ​​en la pila, los marcadores de posición del valor de retorno y los bytes de alineación) en toda la pila de llamadas excede ese límite, obtendrá un desbordamiento de la pila, que generalmente elimina programa sin ninguna posibilidad de recuperación.

Unos pocos kilobytes suelen estar bien. Decenas de kilobytes son peligrosos porque comienzan a resumir. Cientos de kilobytes es una muy mala idea.


1
¿No es el límite de pila típico de varios megabytes (es decir, generalmente más de uno, pero probablemente menos de una docena) hoy en 2016? En mi escritorio Linux, son 8Mbytes por defecto ...
Basile Starynkevitch

"En [...] Linux, el tamaño máximo típico para una pila es 1 MB" $ ulimit -aen mi sistema, entre otros stack size (kbytes, -s) 8192.
Murphy

9

La única respuesta válida es vaga: "demasiado es cuando la pila se desborda".

A menos que tenga el control total sobre la implementación de cada línea de código entre el punto de entrada del programa y la función en cuestión, no puede hacer suposiciones sobre la cantidad de pila disponible. No puede, por ejemplo, garantizar que llamar a esta función nunca provocará un desbordamiento de la pila:

void break_the_camels_back()
{
    int straw;
    ...
}

La pila predeterminada de 8 MiB en Unixes modernos es bastante espacio para las pilas, especialmente para alguien como yo que es lo suficientemente geezer como para recordar CPU con punteros de pila de 8 bits. La realidad práctica es que es poco probable que lo superes sin intentarlo. Si lo hace, exceder el límite de la pila generalmente se considera una violación de segmentación, y los sistemas con suficiente administración de memoria para detectarlo enviarán un mensaje SIGSEGVcuando ocurra.

Tienes un par de opciones. Primero es no adivinar cuánta pila hay disponible y preguntarle al sistema. Todo lo que se ajuste a POSIX tendrá una getrlimit(2)función que le indicará el límite superior. RLIMIT_STACKes el límite específico que quieres. El segundo es monitorear la cantidad de pila que usan sus programas y tomar decisiones sobre las variables automáticas frente a la asignación de memoria dinámica en función de eso. Hasta donde yo sé, no hay funciones estándar para determinar cuánto de la pila se usa, pero programas como valgrindpueden analizarlo por usted.


4

Si asigna una matriz de, digamos, 10,000 bytes en la pila, entonces esa matriz tiene un tamaño limitado. 10,000 puede ser mucho, pero si necesita 10,001 bytes, entonces su programa puede fallar o peor. Entonces, en esta situación, desea algo que se adapte al tamaño que necesita, y ese algo no estará en la pila.

Las matrices de tamaño fijo para las memorias intermedias de cadenas en la pila no son un problema porque mantienen la memoria en la pila, son un problema porque las memorias intermedias de tamaño fijo son un problema fatal a la espera de que suceda.

Pero si usa C ++ y declara, por ejemplo, un std :: string o un std :: vec en la pila, entonces lo que está en la pila será en realidad de un tamaño fijo y pequeño. Los datos reales se almacenarán en el montón. Puede almacenar un millón de caracteres en una instancia de std :: string, y solo tomará una cantidad muy pequeña de datos (generalmente de 8 a 24 bytes, dependiendo de la implementación) en la pila, y un millón de bytes en el montón.


2

Bueno, 1 MB es una buena estimación para * nix. La recursión puede ser una razón importante para el desbordamiento de la pila en combinación con las asignaciones de pila. Sin embargo, en la mayoría de los casos, los objetos divinos que superficialmente parecerían demasiado grandes para colocarlos en la pila están bien diseñados para administrar su memoria interna en el montón y usar la pila solo como una forma de ser destruidos automáticamente cuando la pila se abre. El destructor liberará los enormes fragmentos de memoria gestionados internamente. Los contenedores estándar están diseñados de esa manera, y los punteros compartidos / únicos también están diseñados de esa manera.

Lo importante es no asignar grandes fragmentos de memoria sin formato en la pila como char [1024 * 1024] y diseñar clases para ajustar las asignaciones de almacenamiento dinámico y usar la pila solo por la conveniencia de llamar automáticamente al destructor.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.