Es un área de memoria reservada en los sistemas Windows.
Método de asignación de memoria:
1. Asignación de memoria estática
La memoria se asigna cuando se compila el programa y esta memoria siempre existe durante la ejecución del programa. . Por ejemplo, variables globales y variables estáticas. 2. Asignación del área de la pila Durante la ejecución de la función, se pueden crear en la pila unidades de almacenamiento para variables locales dentro de la función. Estas unidades de almacenamiento se liberarán automáticamente al final de la ejecución de la función. Las operaciones de asignación de memoria de pila están integradas en el conjunto de instrucciones del procesador y son muy eficientes, pero la capacidad de memoria asignada es limitada.
3. Asignación de montón
También se llama asignación de memoria dinámica. Un programa aplica cualquier cantidad de memoria en tiempo de ejecución usando malloc o new, y el programador es responsable de cuándo se libera o elimina la memoria. La vida útil de la memoria dinámica la determina el programador y su uso es muy flexible. Sin embargo, si se asigna espacio en el montón, el programa es responsable de recuperarlo. De lo contrario, el programa en ejecución tendrá pérdidas de memoria y asignará y liberará montones con frecuencia. El espacio de diferentes tamaños provocará la fragmentación del montón.
Espacio de memoria del programa:
1. Área de pila (pila): asignada y liberada automáticamente por el compilador, utilizada para almacenar variables locales, parámetros de funciones y devolver datos asignados al ejecutar funciones. , dirección del remitente, etc. Opera como una estructura de datos de pila.
2. Montón: generalmente asignado y liberado por el programador. Si el programador no lo libera, el sistema operativo puede restaurarlo una vez finalizado el programa. El método de asignación es similar a una lista vinculada.
3. Área global (área estática) (área estática): almacena variables globales, datos estáticos y constantes. Liberado por el sistema cuando finaliza el programa.
4. Área de constantes de texto: aquí se colocan cadenas constantes. Liberado por el sistema cuando finaliza el programa.
5. Área de código de programa: almacena el código binario del cuerpo de la función (funciones miembro de la clase y funciones globales).
El siguiente programa de muestra:
int?a?=?0;?// ¿Área de inicialización global?
char?*p1;?// ¿Área global no inicializada?
int?main()?{
Int?
Int?b;?
char?s[] =? " abc";?
char?s[]?
char?*p2;?
char?*p2;?
char?*p3?=?"123456";?//123456 está ubicado en el área constante y p3 está ubicado en la pila.
¿estática?
p1 = nuevo carácter[10];?
p2?=?nuevo?char[20];?
//El área asignada para obtener bytes y bytes se encuentra en el área del montón.
strcpy(p1,?" 123456");?// 123456 está en el área constante y el compilador puede optimizarlo para que esté en la misma ubicación que "123456" señalado por p3.
}?
3.¿Montar y apilar?
3.1 Método de aplicación
Pila: asignada automáticamente por el sistema. Por ejemplo, declare una variable local int b en una función; el sistema abre automáticamente espacio para b en la pila.
Montón: los programadores deben solicitar y especificar el tamaño, utilizando la función malloc en lenguaje C y el operador new en C++.
Por ejemplo, p1 = (char *)malloc(10); p1 = nuevo char[10]
Por ejemplo, p2 = (char *)malloc(10); p2 = new char[20];
Pero tenga en cuenta que p1 y p2 están en la pila.
3.2 Respuesta del sistema después de ejecutar la aplicación
Pila: Siempre que el espacio restante en la pila sea mayor que el espacio solicitado, el sistema proporcionará memoria para el programa, de lo contrario Se informará una excepción, lo que indica un desbordamiento de pila.
Montón: En primer lugar debes saber que el sistema operativo dispone de una lista enlazada que registra las direcciones de memoria libre. Cuando el sistema recibe la aplicación del programa, recorrerá la lista vinculada, encontrará el primer nodo del montón con un espacio mayor que el espacio solicitado, luego eliminará el nodo de la lista vinculada de nodos libres y asignará el espacio del nodo al programa. .
Para la mayoría de los sistemas, el tamaño de esta asignación se registra en la primera dirección del espacio de memoria para que las declaraciones de eliminación en el código puedan liberar adecuadamente el espacio de memoria.
Dado que el tamaño del nodo del montón encontrado puede no ser exactamente igual al tamaño solicitado, el sistema automáticamente colocará el exceso nuevamente en la lista libre.
3.3 Limitaciones en el tamaño de la aplicación
Pila: En Windows, la pila es una estructura de datos que se extiende hacia abajo hasta la dirección inferior. Es un área de memoria continua. Lo que esta oración significa es que la dirección de la capa superior de la pila y la capacidad máxima de la pila están predeterminadas por el sistema. En WINDOWS, el tamaño de la pila es 2 M (algunos dicen 1 M, en resumen, es una constante). determinado en el momento de la compilación). Si la aplicación Si el espacio excede el espacio restante de la pila, se generará un desbordamiento. Por tanto, el espacio disponible en la pila es muy pequeño.
Montón: El montón es una estructura de datos que se extiende a direcciones superiores y es un área de memoria no contigua. Esto se debe a que el sistema utiliza una lista vinculada para almacenar direcciones de memoria libre, y la lista vinculada es naturalmente discontinua y la dirección transversal de la lista vinculada es de la dirección baja a la dirección alta. El tamaño del montón está limitado por la cantidad de memoria virtual disponible en el sistema informático. Por tanto, el montón puede ganar más flexibilidad y mayor espacio.
3.4 Comparación de la eficiencia de la aplicación
El sistema asigna automáticamente el montón y es más rápido. Pero el programador no tiene control sobre ello.
El montón es memoria recién asignada. Generalmente es más lento y propenso a la fragmentación de la memoria, pero es el más conveniente de usar.
Además, en WINDOWS, la mejor forma de asignar memoria es utilizar VirtualAlloc. No está en el montón ni en la pila, pero asigna memoria directamente en el proceso de reservar el espacio de direcciones. Lo más inconveniente. Pero es rápido y más flexible.
3.5 Contenido de almacenamiento del montón y la pila
Pila: en una llamada de función, la primera instrucción después de la función principal se inserta en la pila (la siguiente declaración ejecutable de la llamada de función declaración), luego los parámetros de la función. En la mayoría de los compiladores de C, los parámetros se insertan en la pila de derecha a izquierda, seguidos de las variables locales de la función. Tenga en cuenta que las variables estáticas no van a la pila.
Cuando finaliza la llamada a la función, las variables locales primero salen de la pila, luego los parámetros y finalmente el puntero superior de la pila apunta a la dirección donde se almacenó originalmente, que es la siguiente instrucción de la función principal. El programa continúa desde este punto ejecutándose.
Montón: normalmente, se utiliza un byte en el encabezado del montón para almacenar el tamaño del montón. El contenido específico del montón lo organiza el programador.
3.6 Comparación de la eficiencia del acceso
char s1[] = "a";
char *s2 = "b";
a se asigna en tiempo de ejecución; y b se determina en tiempo de compilación; sin embargo, una matriz en la pila es más rápida en accesos posteriores que una cadena a la que apunta un puntero (como el montón).
Por ejemplo:
int main(){?
char?a?=?1;?
char?1234567890";?
char?*p?="1234567890";?
a?=?c[1];?
a?=?p[1];?
¿devolución?
}?
Código ensamblador correspondiente
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
El primero lee directamente los elementos de la cadena en el registro cl, mientras que el segundo primero debe leer el valor del puntero en edx, y luego lea de acuerdo con edx. La obtención de caracteres es obviamente más lenta.
3.7 Resumen
Las principales diferencias entre el montón y la pila son las siguientes:
1. ;
2. Diferentes tamaños de espacio;
3. Diferentes si se pueden generar fragmentos;
4. Diferentes direcciones de crecimiento;
>5. Diferentes métodos de asignación;
6. Diferentes eficiencias de asignación
Método de administración: para la pila, el compilador lo administra automáticamente y no requiere control manual para el montón; , está controlado por el programador y es fácil. Se produce una pérdida de memoria.
Tamaño del espacio: en términos generales, en un sistema de 32 bits, la memoria del montón puede alcanzar 4G. límite para la memoria del montón. Pero para la pila, generalmente no hay límite. Por ejemplo, en VC6, el tamaño del espacio de pila predeterminado es 1M. >
Fragmentación: para el montón, la creación/eliminación frecuente inevitablemente provocará una discontinuidad en el espacio de memoria, lo que dará como resultado una gran cantidad de fragmentos, lo que reduce la eficiencia del programa. Para la pila, este problema no existe, porque la pila es una. Cola de primero en entrar, primero en salir, y existe una correspondencia uno a uno, por lo que siempre estarán allí. Es imposible extraer un bloque de memoria del medio de la pila antes de que se extraiga. , el contenido de arriba se extrajo de la parte posterior de la pila. Para obtener estructuras de datos detalladas, consulte
Dirección de crecimiento: para el montón, la dirección es hacia arriba, es decir, la dirección en la que. la dirección de memoria aumenta; para la pila, la dirección de crecimiento es hacia abajo, es decir, la dirección en la que disminuye la dirección de memoria.
Asignación: el montón se asigna dinámicamente, no hay un montón asignado estáticamente. Hay dos formas de asignar el montón: asignación estática y asignación dinámica. La asignación estática la realiza el compilador, como la asignación de variables locales. La asignación dinámica la completa la función malloca, pero la asignación dinámica de la pila es diferente de la del montón. Su asignación dinámica la libera el compilador y no requiere que la implementemos manualmente.
Eficiencia de asignación: la pila es una estructura de datos proporcionada por el sistema de la máquina. La computadora proporcionará soporte en la parte inferior de la pila: se asignan registros especiales para almacenar la dirección de la pila, y hay registros especiales. instrucciones para empujar y hacer estallar la pila. Esto determina que la eficiencia de la pila es relativamente alta. El montón lo proporciona la biblioteca C/C++ y su mecanismo es muy complejo. Por ejemplo, para asignar una parte de memoria, la función de la biblioteca seguirá un determinado algoritmo (para algoritmos específicos, consulte la estructura de datos/). sistema operativo) para encontrar un espacio disponible lo suficientemente grande en la memoria del montón. Si no hay suficiente espacio (puede deberse a demasiados fragmentos de memoria), si no hay suficiente espacio (puede deberse a demasiados fragmentos de memoria), Puede llamar a la función del sistema para aumentar el espacio del segmento de datos del programa, de modo que exista la posibilidad de asignar suficiente memoria grande y regresar. Obviamente, la eficiencia del montón es mucho menor que la de la pila.
Desde aquí podemos ver que, en comparación con la pila, el montón causa fácilmente una gran cantidad de fragmentos de memoria debido al uso de una gran cantidad de elementos nuevos/eliminados debido a la falta de soporte del sistema especializado; la eficiencia es muy baja debido a la posibilidad de que la activación de cambios de memoria entre el modo de usuario y el modo de núcleo de la aplicación se vuelva más costosa. Por lo tanto, la pila es la más utilizada en los programas. Incluso las llamadas a funciones se completan utilizando la pila. Los parámetros, la dirección de retorno, la EBP y las variables locales durante la llamada a la función se almacenan en la pila. Por lo tanto, recomendamos utilizar la pila en lugar del montón siempre que sea posible.
Aunque la pila tiene muchas ventajas, ya que no es tan flexible como el montón, a veces es mejor utilizar el montón para asignar grandes cantidades de espacio de memoria.
Ya sea un montón o una pila, es muy importante evitar los límites (a menos que lo dejes intencionalmente fuera de los límites), porque los límites harán que el programa bloquear o destruir el montón y las estructuras de pila del programa, lo que produce resultados inesperados.
4.new/delete y malloc/free
Desde una perspectiva de C++, usar new para asignar espacio de almacenamiento dinámico llamará al constructor de la clase, y la función malloc() es simplemente a Una llamada a función que llama al constructor y acepta un parámetro largo sin firmar. Del mismo modo, eliminar llama al destructor antes de liberar el espacio del montón, pero la función libre no lo hace.
clase?Tiempo{?
público:?
Tiempo(int,int,int,cadena);?
~Tiempo (){?
cout<< "call?Time's?destructor?by:"< }? privado: ? int? int? int?sec;? cadena? };? Tiempo::Tiempo(int?h,int?m,int?s,string?n){? hora=h;? min =m;? seg=s;? nombre=n;? cout<< "llamar?Time's?constructor?by:"<< nombre< }? int?main(){? ¿Tiempo?*t1;? t1 =(Tiempo*)malloc(tamañode(Tiempo));? libre(t1);? Tiempo?*t2;? t2=nuevoTiempo (0,0,0, "t2");? eliminar?t2;? sistema("PAUSA");? regresar?EXIT_SUCCESS ;? }? Resultado: Constructor de Call Time: t2 Destructor de Call Time: t2 Como se puede ver en los resultados, usar new/delete puede llamar al constructor y al destructor del objeto, y este ejemplo llama a un constructor no predeterminado. Sin embargo, al asignar una matriz de objetos en el montón, solo se puede llamar al constructor predeterminado y no a ningún otro constructor.