Procesar el espacio de direcciones en Linux (requerido para principiantes)

contenido

1. Espacio de direcciones del programa

2. Espacio de direcciones del proceso


1. Espacio de direcciones del programa

Primero, revisemos el espacio de direcciones del programa en c/c++ a través de una imagen:

 Aquí hay una breve introducción a estas áreas:

1. Área de montón:

El área de datos del montón es el área del montón.En el programa C, la asignación y recuperación de esta área se realizan mediante mallocy free. A medida que avanza la asignación del área, el área continúa extendiéndose desde la dirección inferior a la dirección superior.

2. Área de pila:

El área de la pila, cuando el programa se está ejecutando, la pila generada por la llamada a la función se almacena en esta área. La dirección de inicio de esta área es fija (junto al área de memoria del núcleo), y como la pila se genera al llamar funciones, esta área continúa extendiéndose desde direcciones altas a direcciones bajas.

3. Área de código y datos:

El contenido del archivo de programa ejecutable se carga en esta área, que se divide en dos partes. La parte de la dirección baja contiene el código del programa y los datos de solo lectura, que es la parte de solo lectura; la otra área almacena los datos de lectura y escritura. datos del archivo ejecutable, que es la parte de solo lectura, área de lectura y escritura.

4. Área de memoria del núcleo:

El área de memoria virtual del núcleo, en un bloque de espacio de direcciones en la dirección más alta del espacio de direcciones virtuales. Los procesos de usuario no pueden acceder a esta área.

El título verifica el segmento del espacio de direcciones de la figura anterior a través de una representación simple:

#include<stdio.h>                                                                                                                                           
  2 #include<iostream>
  3 using namespace std;
  4   int g_unval;
  5  int g_val=0;
  6  int main()
  7  {
  8    printf("code addr:%p\n",main);//打印代码区的地址
  9    const char*str="ddddddd";
 10    printf("string rdonly addr %p\n",str);//打印字符常量区的地址
 11    //打印未初始化全局数据区的地址
 12    printf("uninit addr: %p\n",&g_unval);
 13    //打印已初始化全局数据区
 14    printf("init addr: %p\n",&g_val);
 15   //打印堆区的地址 
 16      int *p1=new int (1);
 17      int *p2=new int(2);
 18      int *p3=new int(3);
 19     printf("heap addr: %p \n",p1);
 20     printf("heap addr: %p \n",p2);
 21     printf("heap addr: %p \n",p3);
 22 
 23 
 24    //打印栈区的地址
 25    int a1=10;
 26    int a2=20;
 27    int a3=30;
 28    printf("stack addr : %p\n",&a1);
 29    printf("stack addr : %p\n",&a2);
 30    printf("stack addr : %p\n",&a3);
 31 
 32    return 0;
 33 }
~

Resultados permitidos:

 Encontré que la rama es de hecho así.

Hagamos un experimento:

#include<unistd.h>
  2 #include<stdio.h>
  3 #include<sys/types.h>
  4 int g_val=10;
  5 int main()
  6 {
  7   pid_t id=fork();
  8   if(id<0)
  9   {
 10     printf("fork fail");
 11   }
 12   else if(id==0)
 13   {
 14    while(1)
 15    {
 16     printf(" I am a child pid:%d  g_val:%d &g_val:%p\n",getpid(),g_val,&g_val);
 17     sleep(2);
 18    }
 19 
 20   }
 21   else
 22   {
 23     while(1)
 24     {
 25       printf("I am a parent pid:%d  g_val :%d &g_val:%p\n",getpid(),g_val,&g_val);                                                                          
 26       sleep(2);
 27     }
 28 
 29   }
 30 
 31   return 0;
 32 }
 33 

Ejecutemos este código:

 El g_val y &g_val impresos por el proceso hijo y el proceso padre son los mismos. No hay problema. Esto es lo mismo que dijimos antes. El código y los datos de los procesos padre e hijo se comparten (bajo la premisa de que no modificación). No hay problema. Veamos un fragmento de código. :

#include<unistd.h>
  2 #include<stdio.h>
  3 #include<sys/types.h>
  4 int g_val=100;                                                                                                                                              
  5 int main()
  6 {
  7   pid_t id=fork();
  8   if(id<0)
  9   {
 10     printf("fork fail");
 11   }
 12   else if(id==0)
 13   {
 14     int cnt=0;
 15    while(1)
 16    {
 17      cnt++;
 18      if(cnt==3)
 19      {
 20        g_val=10;
 21        printf("子进程修改g_val\n");
 22      }
 23     printf(" I am a child pid:%d  g_val:%d &g_val:%p\n",getpid(),g_val,&g_val);
 24     sleep(2);
 25    }
 26 
 27   }
 28   else
 29   {
 30     while(1)
 31     {
 32       printf("I am a parent pid:%d  g_val :%d &g_val:%p\n",getpid(),g_val,&g_val);
 33       sleep(2);
 34     }
 35 
 36   }
 37 
 38   return 0;
 39 }
 40 
                                                                              
                                              

Ejecutemos este programa:

 Encontramos que luego de que el proceso hijo modifica el valor de g_val, ocurre copy-on-write porque los procesos son independientes.Podemos entender que los valores impresos por el proceso hijo y el proceso padre son diferentes, pero nos sorprendemos al encontrar que sus direcciones son las mismas. Si se trata de una dirección física, ¿cómo es posible tomar los contenidos del mismo espacio y no del mismo? Entonces podemos obtener:

Esto definitivamente no es una dirección física. Bajo la dirección de Linux, este tipo de dirección se llama dirección virtual.¡Las direcciones que vemos en el lenguaje C/C++ son todas direcciones virtuales! La dirección física es invisible para el usuario y está gestionada por el sistema operativo.

2. Espacio de direcciones del proceso

Así que dijimos antes que 'el espacio de direcciones del programa' no es exacto, debería ser el espacio de direcciones del proceso. El espacio de direcciones del proceso es una estructura creada por el sistema operativo. El título se llama mm_struct. El espacio de direcciones virtuales se divide. Su dirección virtual es de (0x 00 00 00 00 a oxff ff ff ff) y es administrado por el mismo otro proceso PCB del bloque de control Su propio espacio de direcciones de proceso, es decir, cada proceso piensa que es un recurso exclusivo y piensa que tiene 4GB de espacio (bajo plataformas de 32 bits). Entonces, el espacio de direcciones del proceso es en realidad un espacio de direcciones virtual. ¡El espacio de direcciones virtuales también se puede considerar como la dirección virtual de la posición lineal correspondiente cuando el área se divide en el espacio de direcciones!

Espacio de direcciones virtuales Cada proceso tiene un espacio de direcciones virtuales y el sistema operativo asigna la dirección virtual a la dirección física a través de una determinada relación de asignación, lo que corresponde a la dirección física real.

 Y este trabajo de conversión es la legendaria tabla de páginas. Podemos explicar el fenómeno anterior a continuación. La creación del proceso secundario toma el proceso principal como plantilla, por lo que los procesos principal y secundario tienen espacios de direcciones virtuales, y el contenido es básicamente el mismo (parte de los datos es diferente), y la relación de mapeo de la tabla de páginas es secundaria El proceso es el mismo que el proceso principal. Cuando el proceso secundario modifica los datos, el sistema operativo interrumpirá el proceso secundario para abrir un nuevo espacio para copiar los datos y luego permitirá que el proceso secundario proceso modificar el espacio recién abierto. Aunque la dirección física ha cambiado, la dirección virtual no ha cambiado, lo que significa cambiar la relación de asignación entre la dirección virtual y la dirección física en el proceso secundario. Entonces, las direcciones virtuales son las mismas cuando las direcciones que vimos antes son de la misma naturaleza.

 Ahora podemos entender cómo los procesos padre e hijo son independientes. El código y los datos del proceso padre-hijo se comparten, pero siempre que una de las partes intente escribir en él, también copiará sobre escritura, modificando la relación entre el mapeo en la tabla de páginas y la memoria física, de modo que el El proceso padre-hijo tiene sus propios datos, logrando Independencia

¿Por qué está diseñado de esta manera?

Razón uno:

Con el espacio de direcciones virtuales, el proceso de acceso a la memoria física no puede acceder directamente a la memoria física, y se agrega una capa intermedia (tabla de páginas), que es más propicia para la operación de administración de la memoria. De esta forma, cada proceso debe acceder a la memoria física correspondiente a través del espacio de direcciones virtuales y la tabla de páginas, el sistema operativo puede intervenir al convertir la dirección virtual a una dirección física para determinar si es una dirección física legal después de la conversión, de modo que para proteger la memoria física.

Razón dos:

Los conceptos de aplicación de memoria y uso de memoria están claramente divididos en el tiempo, y una serie de operaciones de la aplicación subyacente están protegidas a través del espacio de direcciones virtuales, para que el sistema operativo pueda administrar mejor la memoria y los procesos.

Razón tres:

Con un espacio de direcciones virtuales, cada proceso considera su propio recurso de memoria exclusivo y ve la memoria de la misma manera. Esto mejora en gran medida la eficiencia de gestión del sistema operativo.

Por ejemplo: cuando la CPU ejecuta el código, primero necesita encontrar la posición de inicio del programa, es decir, la dirección de inicio. Con el espacio de direcciones virtuales, solo necesita encontrar la dirección virtual fija. El espacio de direcciones de proceso de diferentes procesos tienen diferentes relaciones de mapeo, por lo que esta dirección virtual fija se asigna a diferentes direcciones físicas en diferentes procesos, y se buscan el código y los datos relacionados con el proceso, para que la CPU pueda encontrar rápidamente la posición inicial del programa.

Razón cuatro:

El espacio de direcciones virtuales puede hacer que las direcciones sean contiguas y reducir la probabilidad de acceso anormal y fuera de los límites.

Vuelva a comprender el proceso y la creación de procesos:

1. ¿Qué es un proceso? Un proceso es un programa cargado en la memoria, que incluye código, datos y una estructura de datos creada por el sistema operativo para él (PCB (task_struct) + mm_struct (espacio de direcciones del proceso) + tabla de páginas. Y podemos encontrar la mm_struct correspondiente a través de la PCB. .

Supongo que te gusta

Origin blog.csdn.net/qq_56999918/article/details/123938638
Recomendado
Clasificación