¿Por qué Windows reserva 1 Gb(o 2 Gb) para su espacio de direcciones del sistema?
memory virtual (6)
El código que se ejecuta en modo kernel (es decir, el código del controlador del dispositivo) tiene su propio espacio de direcciones.
No, no lo hace. Tiene que compartir ese espacio de direcciones con la parte de modo de usuario de un proceso en procesadores x86. Es por eso que el núcleo tiene que reservar espacio suficiente en total y finito el espacio de direcciones.
Es un hecho conocido que las aplicaciones de Windows generalmente tienen 2 GB de espacio de direcciones privadas en un sistema de 32 bits. Este espacio se puede ampliar a 3Gb con el interruptor / 3Gb.
El sistema operativo se reserva el resto de los 4Gb.
Mi pregunta es ¿POR QUÉ?
El código que se ejecuta en modo kernel (es decir, el código del controlador del dispositivo) tiene su propio espacio de direcciones. ¿Por qué, además de un espacio de direcciones exclusivo de 4Gb, el sistema operativo todavía desea reservar 2Gb de cada proceso en modo de usuario?
Pensé que la razón es la transición entre el modo de usuario y la llamada de modo kernel. Por ejemplo, una llamada a NtWriteFile
necesitará una dirección para la rutina de envío del kernel (de ahí que el sistema reserve 2Gb en cada aplicación). Pero, usando SYSENTER
, ¿no es el número de servicio del sistema suficiente para que el código del modo de núcleo sepa a qué función / servicio se está llamando?
Si pudiera explicarme por qué es tan importante para el sistema operativo tomar 2 Gb (o 1 Gb) de cada proceso en modo de usuario.
Creo que la mejor respuesta es que los diseñadores del sistema operativo sintieron que para el momento en que tendrías que preocuparte, la gente estaría usando Windows de 64 bits.
Pero aquí hay una mejor discusión .
Dos procesos de usuario diferentes tienen diferentes espacios de direcciones virtuales. Debido a que las asignaciones de direcciones físicas y virtuales son diferentes, la caché TLB se invalida cuando se cambian los contextos de un proceso de usuario a otro. Esto es muy costoso, ya que sin la dirección ya almacenada en la memoria caché en el TLB, cualquier acceso a la memoria resultará en una falla y una caminata de los PTE .
Syscalls involucra dos cambios de contexto: usuario → kernel, y luego kernel → usuario. Para acelerar esto, es común reservar el mayor espacio de direcciones virtuales de 1GB o 2GB para el uso del kernel. Debido a que el espacio de direcciones virtuales no cambia a través de estos cambios de contexto, no se necesitan vaciados TLB. Esto se habilita mediante un bit de usuario / supervisor en cada PTE, lo que garantiza que solo se pueda acceder a la memoria del kernel mientras esté en el kernelspace; El espacio de usuario no tiene acceso aunque la tabla de páginas sea la misma.
Si hubiera soporte de hardware para dos TLB independientes, con uno exclusivo para el uso del kernel, entonces esta optimización ya no sería útil. Sin embargo, si tiene suficiente espacio para dedicar, probablemente valga la pena hacer un TLB más grande.
Linux en x86 una vez admitió un modo conocido como "división 4G / 4G". En este modo, el espacio de usuario tiene acceso completo a todo el espacio de direcciones virtuales de 4GB, y el kernel también tiene un espacio de direcciones virtuales de 4GB. El costo, como se mencionó anteriormente, es que cada syscall requiere una descarga TLB, junto con rutinas más complejas para copiar datos entre el usuario y la memoria del kernel. Esto se ha medido para imponer hasta un 30% de penalización de rendimiento.
Los tiempos han cambiado desde que esta pregunta fue formulada y respondida originalmente: los sistemas operativos de 64 bits ahora son mucho más frecuentes. En los sistemas operativos actuales en x86-64, se permiten las direcciones virtuales de 0 a 2 47 -1 (0-128TB) para los programas de usuario, mientras que el kernel reside permanentemente dentro de las direcciones virtuales de 2 47 × (2 17 -1) a 2 64 -1 (o de -2 47 a -1, si trata las direcciones como enteros con signo).
¿Qué sucede si ejecuta un ejecutable de 32 bits en Windows de 64 bits? Usted pensaría que todas las direcciones virtuales de 0 a 2 32 (0-4GB) estarían fácilmente disponibles, pero para evitar la exposición de errores en programas existentes, los ejecutables de 32 bits todavía están limitados a 0-2GB a menos que se vuelvan a compilar con /LARGEADDRESSAWARE
. Para aquellos que están, tienen acceso a 0-4GB. (Esto no es un nuevo indicador; lo mismo se aplicó en los kernels de Windows de 32 bits que se ejecutan con el conmutador /3GB
, que cambió la división predeterminada de usuario / kernel 2G / 2G a 3G / 1G, aunque, por supuesto, 3-4GB aún estaría fuera de rango.)
¿Qué tipo de errores podría haber? Como ejemplo, supongamos que está implementando quicksort y tiene dos punteros, b
apuntando al principio y más allá del final de una matriz. Si elige el medio como el pivote con (a+b)/2
, funcionará siempre y cuando ambas direcciones estén por debajo de 2GB, pero si ambas están arriba, entonces la adición encontrará un desbordamiento de enteros y el resultado será fuera de la matriz. (La expresión correcta es a+(ba)/2
)
Además, Linux de 32 bits, con su división por defecto de usuario / kernel 3G / 1G, históricamente ha ejecutado programas con su pila ubicada en el rango de 2-3GB, por lo que cualquier error de programación de este tipo probablemente se haya eliminado rápidamente. Linux de 64 bits le da a los programas de 32 bits acceso a 0-4GB.
Parte de la respuesta es hacer con la historia de las arquitecturas de microprocesadores. Aquí hay algo de lo que sé, otros pueden proporcionar detalles más recientes.
El procesador Intel 8086 tenía una arquitectura de desplazamiento de segmento para la memoria, que daba direcciones de memoria de 20 bits y, por lo tanto, una memoria física total direccionable de 1 MB.
A diferencia de los procesadores de la era de la competencia, como el Zilog Z80, el Intel 8086 tenía solo un espacio de direcciones que tenía que acomodar no solo la memoria electrónica, sino toda la comunicación de entrada / salida con periféricos menores como el teclado, los puertos serie, los puertos de la impresora y las pantallas de video. . (A modo de comparación, el Zilog Z80 tenía un espacio de direcciones de entrada / salida separado con códigos de operación de ensamblaje dedicados para el acceso)
La necesidad de dejar espacio para un rango cada vez mayor de expansiones periféricas llevó a la decisión original de segmentar el espacio de direcciones en la memoria electrónica de 0-640K, y "otras cosas" (entrada / salida, ROMS, memoria de video, etc.) de 640K a 1MB.
A medida que la línea x86 creció y evolucionó, y las PC evolucionaron con ellas, se usaron esquemas similares, que terminaron con la división actual 2G / 2G del espacio de direcciones 4G.
Raymond Chen tenía un montón de artículos sobre este tema .
Windows (como cualquier sistema operativo) es mucho más que los controladores de kernel +.
Su aplicación se basa en una gran cantidad de servicios del sistema operativo que no solo existen en el espacio del kernel. Hay muchos buffers, manejadores y todo tipo de recursos que pueden asignarse al propio espacio de direcciones de su proceso. Siempre que llame a una función de la API de Win32 que devuelva, digamos, un manejador de ventana o un pincel, esas cosas deben asignarse en algún lugar de su proceso. Así que parte de Windows se ejecuta en el kernel, sí, otras partes se ejecutan en sus propios procesos de modo de usuario y algunas, a las que su aplicación necesita acceso directo, se asignan a su espacio de direcciones. Parte de esto es difícil de evitar, pero un factor adicional importante es el rendimiento. Si cada llamada a Win32 requiriera un cambio de contexto, sería un gran éxito de rendimiento. Si algunos de ellos se pueden manejar en modo de usuario porque los datos en los que se basan ya están asignados a su espacio de direcciones, se evita el cambio de contexto y se ahorran unos cuantos ciclos de CPU.
Por lo tanto, cualquier sistema operativo necesita cierta cantidad de espacio de direcciones a un lado. Creo que Linux por defecto solo configura 1GB para el sistema operativo.
La razón por la que MS se estableció en 2 GB con Windows se explicó una vez en el blog de Raymond Chen. No tengo el enlace, y no puedo recordar los detalles, pero la decisión se tomó porque Windows NT también estaba dirigido a los procesadores Alpha, y en Alpha, había una buena razón para hacer el 50/50. división. ;)
Tenía algo que ver con el soporte del Alpha para 32, así como con el código de 64 bits. :)