Lección
La teoría — La pila de llamadas: marcos, direcciones de retorno y desbordamientos
La pila de llamadas es una región de memoria donde cada llamada a una función recibe un marco. Aquí contiene su argumento, la dirección de retorno (donde se reanuda la función que hizo la llamada), el puntero de marco guardado de esa función y las variables locales. El puntero de pila señala la dirección más baja en uso; una llamada lo hace bajar un marco y un retorno lo hace subir de nuevo. Una recursión de profundidad d, con marcos de f bytes, necesita d·f bytes de pila.
Qué significa cada símbolo
d- la profundidad: cuántos marcos hay a la vez en la pila
f- los bytes de cada marco: aquí, 12 más 4 por cada variable local
- Supone
- Se supone una máquina de 32 bits con la convención de llamada clásica de C: posiciones de 4 bytes, una pila que crece hacia direcciones más bajas, argumentos que se pasan por la pila y un puntero de marco en cada marco. Las convenciones de 64 bits pasan los primeros argumentos en registros; los compiladores pueden omitir el puntero de marco. En ARM, una función que no llama a ninguna otra puede conservar su dirección de retorno en un registro. Por eso, los marcos reales pueden tener un tamaño y una distribución distintos de los de estas tres posiciones.
Problema resuelto al detalle
-
¿Hasta qué profundidad puede llegar la recursión? 4 pasos
Pulsa fact(11) se desborda. La pila de esta página tiene 128 bytes. El enlazador de Microsoft reserva por defecto 1 MB de pila para un programa; toma ese tamaño como 1 MiB, es decir, 1.048.576 bytes, y usa los marcos de esta página. ¿Hasta qué profundidad puede llegar fact? ¿Y si cada llamada reserva además una variable local de 4 bytes? ¿Cuánta pila necesita fib(30) y cuántas llamadas realiza?
Abre este problema en la herramienta
-
Cada marco contiene un argumento, una dirección de retorno y un puntero de marco guardado: 3 × 4 = 12 bytes. Como 128 / 12 = 10,67, caben 10 marcos, y fact(11) necesita 11 × 12 = 132 bytes. La tabla de resultados muestra el desbordamiento.
-
1.048.576 / 12 = 87.381,33, así que caben 87.381 marcos: fact podría alcanzar 87.381 niveles de recursión antes de agotar la pila. Mucho antes, su resultado ya habría superado lo que cabe en un int de 32 bits: ocurre con 13! = 6.227.020.800.
-
Con una variable local de 4 bytes, cada marco ocupa 16 bytes, y 1.048.576 / 16 = 65.536 exactamente.
-
La cadena más larga de fib(30) tiene 30 marcos: 30 × 12 = 360 bytes. El número de llamadas es 2·F(31) − 1, donde F(31) = 1.346.269 es el término 31 de la sucesión de Fibonacci. En total, 2.692.537 llamadas.
Respuesta
87.381 niveles, o 65.536 con una variable local. fib(30) necesita 360 bytes de pila y realiza 2.692.537 llamadas. La profundidad determina el espacio de pila; en fib, el número de llamadas determina el tiempo.
-
Ruta de aprendizaje
Cómo ejecuta un programa un ordenador
Referencias (2)
- The worked problem's stack size: the linker's default reservation: Microsoft Learn, "/STACK (Stack allocations)," C/C++ build reference, updated 23 February 2022.
- The first insight's 1988 example: fingerd's unbounded read into a 512-byte buffer on the stack: Bob Page, "A Report on the Internet Worm." University of Lowell, 7 November 1988 (copy hosted at Toronto Metropolitan University).