¿Podría ser más eficiente para los sistemas en general eliminar las pilas y simplemente usar Heap para la gestión de la memoria?

14

Me parece que todo lo que se puede hacer con una pila se puede hacer con el montón, pero no todo lo que se puede hacer con la pila se puede hacer con la pila. ¿Es eso correcto? Entonces, para simplificar, e incluso si perdemos un poco de rendimiento con ciertas cargas de trabajo, ¿no sería mejor ir con un solo estándar (es decir, el montón)?

Piense en la compensación entre modularidad y rendimiento. Sé que no es la mejor manera de describir este escenario, pero en general parece que la simplicidad de comprensión y diseño podría ser una mejor opción, incluso si existe un potencial para un mejor rendimiento.

    
pregunta Dark Templar 08.10.2011 - 23:02

11 respuestas

30

Los montones son malos en la rápida asignación y desasignación de memoria. Si desea tomar muchas pequeñas cantidades de memoria por un tiempo limitado, un montón no es su mejor opción. Una pila, con su algoritmo de asignación / desasignación súper simple, naturalmente se destaca en esto (aún más si está integrado en el hardware), por lo que la gente lo usa para cosas como pasar argumentos a funciones y almacenar variables locales: la mayoría La desventaja importante es que tiene espacio limitado, por lo que mantener objetos grandes en él, o intentar usarlo para objetos de larga duración, es una mala idea.

Deshacerse de la pila por completo para simplificar un lenguaje de programación es una forma incorrecta de IMO: un mejor enfoque sería abstraer las diferencias, dejar que el compilador determine qué tipo de almacenamiento utilizar, mientras que el programador pone juntas construcciones de alto nivel que están más cerca de la forma en que los humanos piensan, y de hecho, los lenguajes de alto nivel como C #, Java, Python, etc. hacen exactamente esto. Ofrecen una sintaxis casi idéntica para los objetos asignados al montón y las primitivas asignadas a la pila ('tipos de referencia' vs. 'tipos de valor' en la jerga .NET), ya sea totalmente transparente o con algunas diferencias funcionales que debe entender para usar el lenguaje correctamente (pero en realidad no es necesario saber cómo funcionan internamente una pila y un montón).

    
respondido por el tdammers 09.10.2011 - 00:06
8

En pocas palabras, una pila no es un poco de rendimiento. Es cientos o miles de veces más rápido que el montón. Además, la mayoría de las máquinas modernas tienen soporte de hardware para la pila (como x86) y esa funcionalidad de hardware, por ejemplo. la pila de llamadas no se puede eliminar.

    
respondido por el DeadMG 09.10.2011 - 01:00
8

No

El área de pila en C ++ es increíblemente rápida en comparación. No creo que ningún desarrollador de C ++ con experiencia esté abierto a deshabilitar esa funcionalidad.

Con C ++, tienes opción y tienes control. Los diseñadores no estaban particularmente inclinados a introducir características que agregaran un tiempo o espacio de ejecución significativo.

Ejerciendo esa elección

Si desea crear una biblioteca o programa que requiera que cada objeto se asigne de forma dinámica, puede hacerlo con C ++. Se ejecutaría de forma relativamente lenta, pero luego podría tener esa "modularidad". Para el resto de nosotros, la modularidad es siempre opcional, introdúzcala según sea necesario porque ambos son necesarios para implementaciones buenas / rápidas.

Alternativas

Hay otros idiomas que requieren que el almacenamiento para cada objeto se cree en el montón; es bastante lento, por lo que compromete los diseños (programas del mundo real) de una manera que es peor que tener que aprender ambos (IMO).

Ambos son importantes, y C ++ le brinda el uso de energía de manera efectiva para cada escenario dado. Habiendo dicho eso, el lenguaje C ++ puede no ser ideal para su diseño, si estos factores en su OP son importantes para usted (por ejemplo, lea en idiomas de nivel superior).

    
respondido por el justin 09.10.2011 - 00:27
6
  

Entonces, para simplificar, e incluso si perdemos una pequeña cantidad de   rendimiento con ciertas cargas de trabajo, ¿no podría ser mejor simplemente ir   con un estándar (es decir, el montón)?

¡En realidad, el impacto en el rendimiento probablemente sea considerable!

Como otros han señalado, las pilas son una estructura extremadamente eficiente para administrar datos que obedecen a las reglas LIFO (las últimas en entrar, las primeras en salir). La asignación / liberación de memoria en la pila generalmente es solo un cambio a un registro en la CPU. Cambiar un registro es casi siempre una de las operaciones más rápidas que puede realizar un procesador.

El montón suele ser una estructura de datos bastante compleja y la asignación / liberación de memoria requerirá muchas instrucciones para llevar a cabo toda la contabilidad asociada. Peor aún, en implementaciones comunes, cada llamada para trabajar con el montón tiene el potencial de resultar en una llamada al sistema operativo. ¡Las llamadas al sistema operativo consumen mucho tiempo! Normalmente, el programa tiene que cambiar del modo de usuario al modo de kernel, y siempre que esto suceda, el sistema operativo puede decidir que otros programas tienen necesidades más urgentes y que su programa deberá esperar.

    
respondido por el Charles E. Grant 09.10.2011 - 00:46
5

Simula usó el montón para todo. Poner todo en el montón siempre induce un nivel más de direccionamiento indirecto para las variables locales, y ejerce una presión adicional sobre el recolector de basura (hay que tener en cuenta que los recolectores de basura realmente aspiraron en ese entonces). En parte es por eso que Bjarne inventó C ++.

    
respondido por el fredoverflow 08.10.2011 - 23:07
3

Las pilas son extremadamente eficientes para los datos LIFO, como los metadatos asociados con llamadas a funciones, por ejemplo. La pila también aprovecha las características de diseño inherentes de la CPU. Dado que el rendimiento en este nivel es fundamental para casi todo lo demás en un proceso, el hecho de que ese "pequeño" impacto en ese nivel se propague muy ampliamente. Además, el sistema operativo puede mover la memoria del montón, lo que sería mortal para las pilas. Si bien se puede implementar una pila en el montón, requiere una sobrecarga que afectará literalmente cada pieza de un proceso en el nivel más granular.

    
respondido por el kylben 09.10.2011 - 00:09
2

"eficiente" en términos de que usted escriba código tal vez, pero ciertamente no en términos de eficiencia de su software. Las asignaciones de pila son esencialmente gratuitas (solo se necesitan unas pocas instrucciones de la máquina para mover el puntero de la pila y reservar espacio en la pila para las variables locales).

Dado que la asignación de la pila casi no toma tiempo, una asignación incluso en un montón muy eficiente será 100k (si no 1M +) veces más lenta.

Ahora imagine cuántas variables locales y otras estructuras de datos utiliza una aplicación típica. Cada pequeña "i" que utilice como contador de bucle se asignará un millón de veces más lento.

Claro que si el hardware es lo suficientemente rápido, podría escribir una aplicación que solo use heap. Pero ahora imagine qué tipo de aplicación podría escribir si aprovechara el montón y usara el mismo hardware.

    
respondido por el DXM 09.10.2011 - 00:02
2

Es posible que tenga interés en "La recolección de basura es rápida, pero una pila es más rápida".

enlace

Si lo leí correctamente, estos chicos modificaron un compilador de C para asignar "marcos de pila" en el montón, y luego usan la recolección de basura para desasignar los marcos en lugar de abrir la pila.

Los "cuadros de pila" asignados a la pila superan en forma decisiva a los "cuadros de pila" asignados a la pila.

    
respondido por el Bruce Ediger 09.10.2011 - 05:13
1

¿Cómo va a funcionar la pila de llamadas en un montón? Esencialmente, tendría que asignar una pila en el montón en cada programa, ¿por qué no hacer que el hardware OS + haga eso por usted?

Si quieres que las cosas sean realmente simples y eficientes, solo dale al usuario su parte de memoria y deja que se ocupen de ello. Por supuesto, nadie quiere implementar todo por sí mismo y es por eso que tenemos una pila y un montón.

    
respondido por el Pubby 09.10.2011 - 00:09
1

Se requiere tanto la pila como el montón. Se utilizan en diferentes situaciones, por ejemplo:

  1. La asignación del montón tiene una limitación que sizeof (a [0]) == sizeof (a [1])
  2. La asignación de pila tiene una limitación de que sizeof (a) es una constante de compilación
  3. La asignación del montón puede hacer bucles, gráficos, etc. estructuras de datos complejas
  4. La asignación de pila puede hacer árboles de tamaño de compilación
  5. El montón requiere un seguimiento de la propiedad
  6. La asignación de pila y la desasignación es automática
  7. La memoria del montón se puede pasar fácilmente de un alcance a otro a través de los punteros
  8. La memoria de la pila es local para cada función y los objetos deben moverse al alcance superior para extender su vida útil (o almacenarse dentro de objetos en lugar de dentro de las funciones miembro)
  9. El montón es malo para el rendimiento
  10. La pila es bastante rápida
  11. Los objetos del montón se devuelven desde las funciones a través de los punteros que toman posesión. O shared_ptrs.
  12. Los objetos de la pila se devuelven desde funciones a través de referencias que no toman posesión.
  13. El montón requiere que cada nuevo coincida con el tipo correcto de eliminar o eliminar []
  14. Los objetos de la pila utilizan RAII y las listas de inicialización del constructor
  15. Los objetos del montón pueden inicializarse en cualquier punto dentro de una función, y no pueden usar parámetros de constructor
  16. Los objetos de la pila utilizan parámetros del constructor para la inicialización
  17. El montón usa matrices y el tamaño de la matriz puede cambiar en tiempo de ejecución
  18. La pila es para objetos individuales, y el tamaño se fija en tiempo de compilación

Básicamente, los mecanismos no se pueden comparar en absoluto porque muchos detalles son diferentes. Lo único común con ellos es que ambos manejan la memoria de alguna manera.

    
respondido por el tp1 09.10.2011 - 01:07
1

Las computadoras modernas tienen varias capas de memoria caché además de un sistema de memoria principal grande pero lento. Uno puede hacer docenas de accesos a la memoria caché más rápida en el tiempo requerido para leer o escribir un byte desde el sistema de memoria principal. Por lo tanto, acceder a una ubicación mil veces es mucho más rápido que acceder a 1,000 (o incluso 100) ubicaciones independientes una vez cada una. Debido a que la mayoría de las aplicaciones asignan y desasignan repetidamente pequeñas cantidades de memoria cerca de la parte superior de la pila, las ubicaciones en la parte superior de la pila se utilizan y reutilizan una cantidad enorme, de modo que la gran mayoría (99% en una aplicación típica) Los accesos a la pila pueden manejarse usando memoria caché.

Por el contrario, si una aplicación creara y abandonara repetidamente objetos de montón para almacenar información de continuación, cada versión de cada objeto de pila que se haya creado alguna vez se tendría que escribir en la memoria principal. Incluso si la gran mayoría de estos objetos serían completamente inútiles cuando la CPU quisiera reciclar las páginas de caché en las que comenzaron, la CPU no tendría forma de saberlo. En consecuencia, la CPU tendría que perder mucho tiempo realizando escrituras lentas de información inútil. No es exactamente una receta para la velocidad.

Otra cosa a tener en cuenta es que, en muchos casos, es útil saber que una referencia de objeto pasada a una rutina no se utilizará una vez que la rutina salga. Si se pasan parámetros y variables locales a través de la pila, y si la inspección del código de la rutina revela que no se conserva una copia de la referencia aprobada, entonces el código que llama a la rutina puede estar seguro de que si no hay una referencia externa a la El objeto existía antes de la llamada, ninguno existirá después. Por el contrario, si los parámetros se pasaran a través de objetos de pila, conceptos como "después de una rutina de devoluciones" se vuelven algo más nebulosos, ya que si el código conserva una copia de la continuación, sería posible que la rutina "regrese" más de una vez después de una llamada única.

    
respondido por el supercat 27.10.2012 - 21:09

Lea otras preguntas en las etiquetas