Las PC de hoy tienen una gran cantidad de RAM física, pero aún así, el tamaño de pila de C # es de solo 1 MB para procesos de 32 bits y de 4 MB para procesos de 64 bits ( capacidad de pila en C # ).
¿Por qué el tamaño de la pila en CLR sigue siendo tan limitado?
¿Y por qué es exactamente 1 MB (4 MB) (y no 2 MB o 512 KB)? ¿Por qué se decidió utilizar estas cantidades?
Me interesan las consideraciones y las razones de esa decisión .
c#
stack
clr
stack-size
Nikolay Kostov
fuente
fuente
Thread
constructor. PERO, esto plantea la pregunta, ¿por qué necesita una pila más grande?1572864
tamaño de pila predeterminado en bytes (recuperado usando la API GetCurrentThreadStackLimits Win32). Puedostackalloc
aproximadamente1500000
bytes sin StackOverflowException.Respuestas:
Estás mirando al tipo que tomó esa decisión. David Cutler y su equipo seleccionaron un megabyte como tamaño de pila predeterminado. Nada que ver con .NET o C #, esto se concretó cuando crearon Windows NT. Un megabyte es lo que elige cuando el encabezado EXE de un programa o la llamada de winapi CreateThread () no especifica explícitamente el tamaño de la pila. Que es la forma normal, casi cualquier programador deja que el sistema operativo elija el tamaño.
Esa elección probablemente sea anterior al diseño de Windows NT, la historia es demasiado turbia al respecto. Sería bueno que Cutler escribiera un libro al respecto, pero nunca ha sido escritor. Ha tenido una influencia extraordinaria en la forma en que funcionan las computadoras. Su primer diseño de sistema operativo fue RSX-11M, un sistema operativo de 16 bits para computadoras DEC (Digital Equipment Corporation). Influyó mucho en el CP / M de Gary Kildall, el primer sistema operativo decente para microprocesadores de 8 bits. Lo que influyó mucho en MS-DOS.
Su siguiente diseño fue VMS, un sistema operativo para procesadores de 32 bits con soporte de memoria virtual. Muy exitoso. El siguiente fue cancelado por DEC cuando la compañía comenzó a desintegrarse, sin poder competir con hardware de PC barato. Cue Microsoft, le hicieron una oferta que no pudo rechazar. Muchos de sus compañeros de trabajo también se unieron. Trabajaron en VMS v2, más conocido como Windows NT. DEC se molestó por eso, el dinero cambió de manos para liquidarlo. Si VMS ya eligió un megabyte es algo que no sé, solo conozco RSX-11 lo suficientemente bien. No es improbable.
Suficiente historia. Un megabyte es mucho , un hilo real rara vez consume más de un par de puñados de kilobytes. Entonces, un megabyte es en realidad un desperdicio. Sin embargo, es el tipo de desperdicio que puede permitirse en un sistema operativo de memoria virtual paginada a demanda, ese megabyte es solo memoria virtual . Solo números para el procesador, uno por cada 4096 bytes. En realidad, nunca usa la memoria física, la RAM en la máquina, hasta que realmente la dirige.
Es más excesivo en un programa .NET porque el tamaño de un megabyte se eligió originalmente para adaptarse a los programas nativos. Que tienden a crear grandes marcos de pila, almacenando cadenas y búferes (matrices) en la pila también. Infame por ser un vector de ataque de malware, un desbordamiento de búfer puede manipular el programa con datos. No es la forma en que funcionan los programas .NET, las cadenas y las matrices se asignan en el montón de GC y se comprueba la indexación. La única forma de asignar espacio en la pila con C # es con la palabra clave unsafe stackalloc .
El único uso no trivial de la pila en .NET es el jitter. Utiliza la pila de su hilo para compilar MSIL en código de máquina justo a tiempo. Nunca he visto ni comprobado cuánto espacio requiere, más bien depende de la naturaleza del código y de si el optimizador está habilitado o no, pero un par de decenas de kilobytes es una suposición aproximada. Que de otra manera es como este sitio web obtuvo su nombre, un desbordamiento de pila en un programa .NET es bastante fatal. No queda suficiente espacio (menos de 3 kilobytes) para seguir JIT de manera confiable con cualquier código que intente detectar la excepción. Kaboom al escritorio es la única opción.
Por último, pero no menos importante, un programa .NET hace algo bastante improductivo con la pila. El CLR confirmará la pila de un hilo. Esa es una palabra cara que significa que no solo reserva el tamaño de la pila, sino que también se asegura de que se reserve espacio en el archivo de paginación del sistema operativo para que la pila siempre pueda intercambiarse cuando sea necesario. No confirmar es un error fatal y termina un programa incondicionalmente. Eso solo sucede en una máquina con muy poca RAM que ejecuta demasiados procesos, tal máquina se habrá convertido en melaza antes de que los programas comiencen a morir. Un posible problema hace más de 15 años, no hoy. Los programadores que ajustan su programa para que actúe como un coche de carreras de F1 utilizan el
<disableCommitThreadStack>
elemento en su archivo .config.Fwiw, Cutler no dejó de diseñar sistemas operativos. Esa foto se hizo mientras trabajaba en Azure.
Actualización, noté que .NET ya no confirma la pila. No estoy seguro de cuándo o por qué sucedió esto, ha pasado demasiado tiempo desde que lo comprobé. Supongo que este cambio de diseño ocurrió en algún lugar alrededor de .NET 4.5. Cambio bastante sensato.
fuente
The only way to allocate space on the stack with C# is with the unsafe stackalloc keyword.
: ¿las variables locales, por ejemplo, unaint
declarada dentro de un método, no se almacenan en la pila? Creo que lo son.maxStackSize
de un hilo. No pude encontrarlo en [MSDN] ( msdn.microsoft.com/en-us/library/5cykbwz4(v=vs.110).aspx ). Según sus comentarios, parece que el uso de la pila es mínimo absoluto y puedo usar el valor más pequeño para acomodar el máximo de subprocesos posibles. Gracias.El enlazador especifica el tamaño de pila reservado predeterminado y los desarrolladores pueden anularlo cambiando el valor de PE en el momento del enlace o para un subproceso individual especificando el
dwStackSize
parámetro para laCreateThread
función WinAPI.Si crea un subproceso con el tamaño de pila inicial mayor o igual que el tamaño de pila predeterminado, se redondea al múltiplo más cercano de 1 MB.
¿Por qué el valor es igual a 1 MB para procesos de 32 bits y 4 MB para 64 bits? Creo que debería preguntarle a los desarrolladores que diseñaron Windows o esperar hasta que alguno de ellos responda a su pregunta.
Probablemente Mark Russinovich lo sepa y puedas contactarlo . Tal vez pueda encontrar esta información en sus libros de Windows Internals anteriores a la sexta edición que describe menos información sobre las pilas en lugar de su artículo . O tal vez Raymond Chen conoce las razones ya que escribe cosas interesantes sobre los componentes internos de Windows y su historia. Él también puede responder tu pregunta, pero debes publicar una sugerencia en el Buzón de sugerencias .
Pero en este momento intentaré explicar algunas razones probables por las que Microsoft ha elegido estos valores utilizando los blogs de MSDN, Mark y Raymond.
Los valores predeterminados tienen estos valores probablemente porque en los primeros tiempos las PC eran lentas y la asignación de memoria en la pila era mucho más rápida que la asignación de memoria en la pila. Y dado que las asignaciones de pila eran mucho más baratas, se utilizaron, pero requirieron un tamaño de pila mayor.
Por tanto, el valor era el tamaño de pila reservado óptimo para la mayoría de las aplicaciones. Es óptimo porque permite hacer muchas llamadas anidadas y asignar memoria en la pila para pasar estructuras a funciones de llamada. Al mismo tiempo, permite crear muchos hilos.
Hoy en día, estos valores se utilizan principalmente para la compatibilidad con versiones anteriores, porque las estructuras que se pasan como parámetros a las funciones de WinAPI todavía se asignan en la pila. Pero si no está utilizando asignaciones de pila, el uso de pila de un hilo será significativamente menor que el 1 MB predeterminado y es un desperdicio, como mencionó Hans Passant. Y para evitar esto, el sistema operativo compromete solo la primera página de la pila (4 KB), si no se especifica otra en el encabezado PE de la aplicación. Otras páginas se asignan bajo demanda.
Algunas aplicaciones anulan el espacio de direcciones reservado e inicialmente se comprometieron a optimizar el uso de la memoria. Como ejemplo, el tamaño máximo de pila de un subproceso de un proceso nativo de IIS es 256 KB ( KB932909 ). Y Microsoft recomienda esta disminución de los valores predeterminados :
Fuentes:
fuente