Espacio de direcciones virtuales
Como todos sabemos virtual significa falso, irreal, ficticio… de ahí el nombre de memoria virtual (porque no es auténtica memoria RAM). Pero... ¿porqué se llama espacio privado de direcciones virtuales? Pues porque es un rango de direcciones falso. Simplemente se trata de una numeración que Windows asigna a las páginas de memoria. Cuando Windows nos dice que una variable está almacenada en la posición 0x00000123, no es que esté en esa posición en RAM, sino que le ha asignado la casilla 123 a nuestra variable. Así cada proceso (o programa) en ejecución tendrá su propio espacio de direcciones (de ahí lo de “privado”) y un proceso no puede acceder a los datos de otro, porque no tiene ninguna forma de referenciarlos.
Pongamos un ejemplo más cotidiano: Si nosotros entramos al portal número 22 de la calle “X”, no significa que estemos entrando en el portal número 22 de la calle “Y”. Del mismo modo, si accedemos a la posición de memoria 22 del proceso “X”, no estamos accediendo a la posición 22 del proceso “Y”, ya que ambas posiciones de memoria son independientes. Del mismo modo, si se cae el edificio del portal 22 de la calle “X”, el de la calle “Y” seguirá en su sitio. Así cuando alguna operación escribe en una dirección equivocada, estará sobrescribiendo un dato de su mismo proceso, pero no de otros, por lo que el único perjudicado es el proceso que escribió mal.
Pero las direcciones virtuales tienen que almacenarse en la memoria, por lo que también estarán situadas en una posición de memoria determinada, así que cada dirección virtual tiene una equivalencia (o proyección) con dirección real, que es donde está almacenado el dato físicamente.
Internamente, Windows es capaz de calcular una dirección física a partir de una dirección virtual, aplicando una serie de algoritmos (que no vamos a detallar). Una vez que ha hecho este cálculo, almacena la equivalencia en una tabla interna, para no tener que recalcular de nuevo la misma dirección.
La estructura de la memoria en Win32 es arbórea, esto es: parte de un nodo raí y después se va subdividiendo en grupos más pequeños, hasta que termina en el más pequeño posible: la página de memoria.
El nodo raíz es una tabla llamada “page map” o Mapa de páginas que se subdivide en:
Page Directory:
Cada proceso cuenta con un solo directorio de páginas, que no es más que una tabla de 1.024 entradas, donde se almacenan los punteros a las 1.024 “Pages Tables” con las que cuenta un proceso.
Page Table:
Cada tabla de páginas es otra tabla (también de 1.024 entradas) donde se almacenan los punteros de los 1.024 “Pages Frames” que posee cada Tabla de páginas.
Page Frame:
Es un bloque de 4 Kb (una página) donde se almacena los datos de cada proceso.
En el siguiente esquema se puede ver este "Page Map":
Nosotros, para hacernos una idea y simplificar un poco este jaleo, lo vamos a representar como una tabla lineal, en la que cada fila será una página de memoria (o un “Page Frame” que viene a ser lo mismo). Algo así como se muestra en la siguiente tabla: