Llame a la función "DoStackOverflow" una vez desde tu codigo y obtendrás el EStackOverflow error provocado por Delphi con el mensaje "desbordamiento de pila".
función DoStackOverflow: entero;
empezar
resultado: = 1 + DoStackOverflow;
final;
¿Qué es esta "pila" y por qué hay un desbordamiento usando el código anterior?
Entonces, la función DoStackOverflow se llama a sí misma recursivamente, sin una "estrategia de salida", simplemente sigue girando y nunca sale.
Una solución rápida, lo haría, es eliminar el error obvio que tiene y asegurarse de que la función exista en algún momento (para que su código pueda continuar ejecutándose desde donde la llamó).
Sigues adelante y nunca miras hacia atrás, sin preocuparte por el error / excepción, ya que ahora está resuelto.
Sin embargo, la pregunta sigue siendo: ¿Qué es esta pila y por qué hay un desbordamiento??
Memoria en sus aplicaciones de Delphi
Cuando comience a programar en Delphi, es posible que experimente un error como el anterior, lo resolverá y continuará. Este está relacionado con la asignación de memoria. La mayoría de las veces no le importaría la asignación de memoria siempre que
libera lo que creas.A medida que adquiere más experiencia en Delphi, comienza a crear sus propias clases, las instancia, se preocupa por la gestión de la memoria y similares.
Llegará al punto donde leerá, en la Ayuda, algo como "Las variables locales (declaradas dentro de los procedimientos y funciones) residen en la aplicación apilar." y también Las clases son tipos de referencia, por lo que no se copian en la asignación, se pasan por referencia y se asignan en montón.
Entonces, ¿qué es "apilar" y qué es "montón"?
Pila vs. Montón
Ejecutando su aplicación en Windows, hay tres áreas en la memoria donde su aplicación almacena datos: memoria global, montón y pila.
Las variables globales (sus valores / datos) se almacenan en la memoria global. La aplicación reserva la memoria para las variables globales cuando se inicia el programa y permanece asignada hasta que finaliza el programa. La memoria para las variables globales se llama "segmento de datos".
Dado que la memoria global solo se asigna y libera una vez al finalizar el programa, no nos importa en este artículo.
La pila y el montón son donde tiene lugar la asignación dinámica de memoria: cuando crea una variable para una función, cuando crea una instancia de una clase cuando envía parámetros a una función y usa / pasa su resultado valor.
¿Qué es la pila?
Cuando declara una variable dentro de una función, la memoria requerida para contener la variable se asigna desde la pila. Simplemente escriba "var x: integer", use "x" en su función, y cuando la función salga, no le importa la asignación de memoria ni la liberación. Cuando la variable se sale del alcance (el código sale de la función), se libera la memoria que se tomó en la pila.
La memoria de la pila se asigna dinámicamente utilizando el enfoque LIFO ("último en entrar, primero en salir").
En Programas Delphi, la memoria de pila es utilizada por
- Variables locales de rutina (método, procedimiento, función).
- Parámetros de rutina y tipos de retorno.
- Función API de Windows llamadas.
- Registros (es por eso que no tiene que crear explícitamente una instancia de un tipo de registro).
No tiene que liberar explícitamente la memoria en la pila, ya que la memoria se asigna automáticamente por arte de magia cuando, por ejemplo, declara una variable local a una función. Cuando la función se cierra (a veces incluso antes debido a la optimización del compilador Delphi), la memoria para la variable se liberará automáticamente.
Tamaño de memoria de pila es, por defecto, lo suficientemente grande para sus programas Delphi (tan complejos como son). Los valores "Tamaño máximo de pila" y "Tamaño mínimo de pila" en las opciones de Linker para su proyecto especifican valores predeterminados: en 99.99% no necesitaría modificar esto.
Piense en una pila como una pila de bloques de memoria. Cuando declara / usa una variable local, el administrador de memoria de Delphi elegirá el bloque desde arriba, lo usará y, cuando ya no sea necesario, volverá a la pila.
Al utilizar la memoria de variables locales de la pila, las variables locales no se inicializan cuando se declaran. Declare una variable "var x: integer" en alguna función e intente leer el valor cuando ingrese la función: x tendrá algún valor "extraño" distinto de cero. Por lo tanto, siempre inicialice (o establezca el valor) en sus variables locales antes de leer su valor.
Debido a LIFO, las operaciones de pila (asignación de memoria) son rápidas ya que solo se requieren unas pocas operaciones (push, pop) para administrar una pila.
¿Qué es el montón?
Un montón es una región de memoria en la que se almacena memoria asignada dinámicamente. Cuando crea una instancia de una clase, la memoria se asigna desde el montón.
En los programas Delphi, la memoria de almacenamiento dinámico es utilizada por / cuando
- Crear una instancia de una clase.
- Creación y cambio de tamaño de matrices dinámicas.
- Asignación explícita de memoria usando GetMem, FreeMem, New y Dispose ().
- Utilizando cadenas ANSI / wide / Unicode, variantes, interfaces (gestionadas automáticamente por Delphi).
La memoria de almacenamiento dinámico no tiene un diseño agradable en el que habría algún orden al asignar bloques de memoria. El montón parece una lata de canicas. La asignación de memoria del montón es aleatoria, un bloque desde aquí que un bloque desde allí. Por lo tanto, las operaciones de almacenamiento dinámico son un poco más lentas que las de la pila.
Cuando solicite un nuevo bloque de memoria (es decir, cree una instancia de una clase), el administrador de memoria de Delphi se encargará de esto por usted: obtendrá un nuevo bloque de memoria o uno usado y descartado.
El montón consta de toda la memoria virtual (RAM y espacio en disco).
Asignación manual de memoria
Ahora que todo lo relacionado con la memoria es claro, puede ignorar de manera segura (en la mayoría de los casos) lo anterior y simplemente continuar escribiendo programas de Delphi como lo hizo ayer.
Por supuesto, debe saber cuándo y cómo asignar / liberar memoria manualmente.
El "EStackOverflow" (desde el principio del artículo) se planteó porque con cada llamada a DoStackOverflow se ha utilizado un nuevo segmento de memoria de la pila y la pila tiene limitaciones. Tan sencillo como eso.