Parece que cada libro .net habla sobre los tipos de valor frente a los tipos de referencia y señala (a menudo incorrectamente) dónde se almacena cada tipo: el montón o la pila. Por lo general, se encuentra en los primeros capítulos y se presenta como un hecho muy importante. Creo que incluso está cubierto en los exámenes de certificación . ¿Por qué es importante apilar vs montón para los desarrolladores (principiantes) .Net? Usted asigna cosas y simplemente funciona, ¿verdad?
36
Respuestas:
Me estoy convenciendo de que la razón principal por la que esta información se considera importante es la tradición. En entornos no administrados, la distinción entre la pila y el montón es importante y tenemos que asignar y eliminar manualmente la memoria que usamos. Ahora, la recolección de basura se encarga de la gestión, por lo que ignoran esa parte. No creo que se haya transmitido realmente el mensaje de que tampoco tenemos que importarnos qué tipo de memoria se usa.
Como Fede señaló, Eric Lippert tiene algunas cosas muy interesantes que decir sobre esto: http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx .
A la luz de esa información, podría ajustar mi primer párrafo para leer básicamente: "La razón por la cual las personas incluyen esta información y asumen que es importante es debido a información incorrecta o incompleta combinada con la necesidad de este conocimiento en el pasado".
Para aquellos que piensan que todavía es importante por razones de rendimiento: ¿Qué acciones tomarían para mover algo del montón a la pila si midieran las cosas y descubrieran que importaban? Lo más probable es que encuentre una forma completamente diferente de mejorar el rendimiento para el área problemática.
fuente
Concuerdo completamente; Veo esto todo el tiempo.
Una parte de la razón es porque muchas personas llegaron a C # (u otros lenguajes .NET) desde un fondo C o C ++. Dado que esos idiomas no le imponen las reglas sobre la vida útil del almacenamiento, debe conocer esas reglas e implementar su programa cuidadosamente para seguirlas.
Ahora, conocer esas reglas y seguirlas en C no requiere que comprenda "el montón" y "la pila". Pero si comprende cómo funcionan las estructuras de datos, a menudo es más fácil entender y seguir las reglas.
Al escribir un libro para principiantes, es natural que un autor explique los conceptos en el mismo orden en que los aprendió. Ese no es necesariamente el orden que tiene sentido para el usuario. Recientemente fui editor técnico del libro para principiantes C # 4 de Scott Dorman, y una de las cosas que me gustó fue que Scott eligió una ordenación bastante sensata para los temas, en lugar de comenzar con lo que realmente son temas bastante avanzados en la gestión de la memoria.
Otra parte de la razón es que algunas páginas en la documentación de MSDN enfatizan fuertemente las consideraciones de almacenamiento. Documentación de MSDN especialmente antigua que todavía se mantiene desde los primeros días. Gran parte de esa documentación tiene errores sutiles que nunca se han eliminado, y debe recordar que fue escrita en un momento particular de la historia y para un público en particular.
En mi opinión, no lo hace. Lo que es mucho más importante de entender es cosas como:
Y así.
Ese es el ideal.
Ahora, hay situaciones en las que sí importa. La recolección de basura es impresionante y relativamente económica, pero no es gratuita. Copiar pequeñas estructuras alrededor es relativamente económico, pero no es gratis. Hay escenarios de rendimiento realistas en los que debe equilibrar el costo de la presión de recopilación con el costo de la copia excesiva. En esos casos, es muy útil tener una sólida comprensión del tamaño, la ubicación y la vida útil real de toda la memoria relevante.
Del mismo modo, hay escenarios de interoperabilidad realistas en los que es necesario saber qué hay en la pila y qué hay en el montón, y qué podría estar moviendo el recolector de basura. Es por eso que C # tiene características como "fijo", "stackalloc", etc.
Pero esos son todos escenarios avanzados. Idealmente, un programador principiante no debe preocuparse por nada de esto.
fuente
Todos ustedes están perdiendo el punto. La razón por la cual la distinción pila / montón es importante es por el alcance .
Una vez que x sale del alcance, el objeto que se creó desaparece categóricamente . Eso es solo porque está asignado en la pila, no en el montón. No hay nada que pueda haber entrado en la parte "..." del método que pueda cambiar ese hecho. En particular, cualquier asignación o llamada a un método solo podría haber hecho copias de la estructura S, no haber creado nuevas referencias para permitirle seguir viviendo.
Historia totalmente diferente! Dado que x está ahora en el montón , su objeto (es decir, el objeto en sí , no una copia del mismo) podría continuar viviendo después de que x salga del alcance. De hecho, la única forma en que no continuará viviendo es si x es la única referencia a ella. Si las asignaciones o llamadas a métodos en la parte "..." han creado otras referencias que aún están "activas" cuando x sale del alcance, entonces ese objeto continuará vivo.
Ese es un concepto muy importante, y la única forma de comprender realmente "qué y por qué" es saber la diferencia entre la asignación de pila y la pila.
fuente
...
podría causarx
que se convierta en un campo de una clase generada por el compilador y, por lo tanto, durar más que el alcance indicado. Personalmente, encuentro desagradable la idea de la elevación implícita, pero los diseñadores de lenguaje parecen ir por ella (en lugar de exigir que cualquier variable que se levante tenga algo en su declaración para especificar eso). Para garantizar la corrección del programa, a menudo es necesario tener en cuenta todas las referencias que puedan existir a un objeto. Saber que para cuando regrese una rutina, no será útil ninguna copia de una referencia pasada.structType foo
, la ubicación de almacenamientofoo
contiene el contenido de sus campos; sifoo
está en la pila, también lo están sus campos. Sifoo
está en el montón, también lo están sus campos. sifoo
está en un Apple II en red, también lo están sus campos. Por el contrario, sifoo
fuera un tipo de clase, contendríanull
o una referencia a un objeto. La única situación en la que sefoo
podría decir que el tipo de clase contiene los campos del objeto sería si fuera el único campo de una clase y tuviera una referencia a sí mismo.En cuanto a POR QUÉ cubren el tema, estoy de acuerdo con @Kirk en que es un concepto importante, que debes entender. Cuanto mejor conozca los mecanismos, mejor podrá hacer para crear excelentes aplicaciones que funcionen sin problemas.
Ahora Eric Lippert parece estar de acuerdo con usted en que la mayoría de los autores no cubren correctamente el tema. Le recomiendo que lea su blog para lograr una gran comprensión de lo que hay debajo del capó.
fuente
Bueno, pensé que ese era el objetivo de los entornos administrados. Incluso iría tan lejos como llamar a esto un detalle de implementación del tiempo de ejecución subyacente sobre el que NO debe hacer ninguna suposición, ya que podría cambiar en cualquier momento.
No sé mucho sobre .NET, pero que yo sepa, está JITED antes de la ejecución. El JIT, por ejemplo, podría realizar un análisis de escape y, de lo contrario, de repente estarías teniendo objetos en la pila o simplemente en algunos registros. No puedes saber esto.
Supongo que algunos libros lo cubren simplemente porque los autores le atribuyen una gran importancia o porque asumen que su audiencia sí (p. Ej., Si escribió un "C # para programadores de C ++", probablemente debería cubrir el tema).
Sin embargo, creo que no hay mucho más que decir que "se gestiona la memoria". De lo contrario, la gente podría sacar conclusiones erróneas.
fuente
Debe comprender cómo funciona la asignación de memoria para usarla de manera eficiente, incluso si no tiene que administrarla explícitamente. Esto se aplica a casi todas las abstracciones en informática.
fuente
Puede haber algunos casos extremos en los que eso puede marcar la diferencia. El espacio de pila predeterminado es 1meg mientras que el montón es de varios conciertos. Entonces, si su solución contiene una gran cantidad de objetos, puede quedarse sin espacio de pila mientras tiene mucho espacio de almacenamiento dinámico.
Sin embargo, en su mayor parte es bastante académico.
fuente
Como usted dice, se supone que C # abstrae la administración de la memoria, y la asignación de pila versus pila son detalles de implementación que, en teoría, el desarrollador no debería necesitar conocer.
El problema es que algunas cosas son realmente difíciles de explicar de forma intuitiva sin hacer referencia a estos detalles de implementación. Intente explicar el comportamiento observable cuando modifique los tipos de valores mutables; es casi imposible hacerlo sin hacer referencia a la distinción pila / montón. O trate de explicar por qué incluso tener tipos de valores en el idioma en primer lugar, y cuándo los usaría. Debe comprender la distinción para que el lenguaje tenga sentido.
Tenga en cuenta que los libros sobre digamos Python o JavaScript no hacen gran cosa si incluso lo mencionan. Esto se debe a que todo está asignado al montón o es inmutable, lo que significa que las diferentes semánticas de copia nunca entran en juego. En esos lenguajes funciona la abstracción de la memoria, en C # es permeable.
fuente