2009-10-08 10 views
5

Comencé a escribir una aplicación grande en C# por primera vez en mi vida. Escribí un módulo de muestra para probar la idea detrás de mi software. Este módulo contenía varias docenas de diccionarios C# y listas de objetos que cada uno tenía varios miembros y propiedades.¿Son las aplicaciones .NET naturalmente intensivas en memoria?

Me sorprendió que después de inicializar núcleo objetos que terminan la utilización de 40 MB de RAM.

Probé y descubrí que se asignan más de 30 MB después de la inicialización de los objetos, pero tenía la impresión de que, dado el tamaño de mis objetos, no deberían haberse consumido más de unos cientos de kilobytes.

¿He hecho algo mal o es .NET, naturalmente, mucha memoria en comparación con las aplicaciones de código nativo?

+4

El tiempo de ejecución es pesado. –

+2

Estoy de acuerdo con usted. Creo que estás haciendo algo terriblemente mal. –

+0

¿Se puede publicar un código de muestra?Creo que será de gran ayuda para entender si es el código que lo causa por sí solo o se está agravando por el tiempo de ejecución –

Respuesta

7

Usando el Administrador de tareas de mirar a su uso de memoria es probable que sea terriblemente inexacta.

En su lugar, agarrar una memoria adecuada herramienta de perfiles (dotTrace es muy buena, y tiene una prueba de 10 días) y se toman el tiempo para ver a su consumo real memoria.

el tipo de cosas que he visto en mi propio código incluyen

  • La subestimación de la cantidad de memoria en realidad estoy usando (sin contar los objetos separados correctamente, que no permite a las listas tienen la capacidad de "reposición")
  • referencias Mantener a objetos transitorios que no necesito
  • no tener en cuenta objetos transitorios creados durante la operación que aún no han sido recolectado
  • no tener en cuenta la memoria no asignada - de memoria que haya sido reclamados desde el sistema operativo (y el refore se muestra como parte del proceso en el Administrador de tareas) pero que no se ha asignado a ningún objeto aún
  • No permite la acumulación de subprocesos (cada subproceso obtiene una pila propia; Las aplicaciones .NET siempre tienen múltiples subprocesos, ya que el framework puede crear varios hilos propios).
2

No siempre se trata del lenguaje, generalmente se trata de cómo se usa.

El código bueno puede usar la memoria de manera eficiente en cualquier idioma.

código incorrecto utilizará la memoria de manera ineficiente en todos los idiomas

+4

Bueno, solo la mitad de verdad. El lenguaje/tiempo de ejecución en este caso * sí * realmente importa un poco. -1 –

+1

Correcto, si le importan unos pocos cientos de K de memoria, C a menudo es una mejor opción. –

+1

¿Qué no es verdad acerca de mi respuesta? (actualizado ligeramente para enfatizar) –

12

¿Cómo se determina la cantidad de memoria que se utilizó? Se sabe que las aplicaciones .NET reservan ansiosamente más memoria de la que necesitan, siempre y cuando haya suficiente memoria disponible, y liberan la memoria al sistema si comienza a escasear la memoria.

Creo que se puede obtener algunos punteros en this MSDN article.

+0

Al usar el administrador de tareas, gracias a que no puede ser un número válido – PiotrK

2

El tiempo de ejecución .Net tiene una cierta gran sobrecarga - hemos encontrado que incluso las aplicaciones sencillas tenderán a utilizar mucha más memoria que las aplicaciones similares escritos en C++. Afortunadamente, esta sobrecarga se disipa rápidamente en el ruido a medida que aumenta el tamaño del código general. El segundo factor es el de la recolección de basura, el recolector de basura se ejecuta "siempre", por lo que, en comparación con C++, las asignaciones de memoria no suelen liberarse de inmediato, sino cuando se siente la necesidad de hacerlo.

5

En los días en que tenemos varios GB de RAM en una máquina, la idea de que una aplicación para usuarios como usted generalmente construya en C# solo debería usar unos 100K de RAM es al revés. Cualquier ram no utilizado en su sistema se desperdicia.

Con esto en mente, C# asigna memoria utilizando la estrategia muy diferente de C++, de manera que los trozos más grandes se asignan y liberan menos frecuencia.

Dicho esto, 40 parece un poco alto. Estoy acostumbrado a algo más cercano a 10-14Mb para aplicaciones de consola muy simples. Tal vez haya una forma tomando Ram, o tal vez estoy en una versión diferente del framework (2.0).

+4

"Se desperdiciará cualquier memoria RAM no utilizada en su sistema". Cualquier RAM que no esté acaparando mi aplicación quizás pueda ser utilizada mejor por otra aplicación o el SO. –

+2

Pero no está siendo 'acallado', está siendo asignado por el tiempo de ejecución de una manera codiciosa. El tiempo de ejecución también puede devolverlo al SO si es necesario. –

+0

una de las principales razones Linux funciona mejor que las ventanas se debe a que utiliza toda la memoria no utilizada como caché de disco, lo que mejora la velocidad de lectura (lo cual es muy necesario debido a la * nix idioma de uso de archivos vacíos como banderas). Si tu aplicación encierra esta memoria, no puede hacer eso. – rmeador

2

Yo diría que a menos que tenga un muy buen motivo para preocuparse por el uso de RAM, no. Al igual que las optimizaciones, solo debe optimizar dónde hay un cliente/usuario final para hacerlo. No creo que los usuarios estén tan limitados por la memoria estos días (a menos que esté hablando de un sistema integrado) que van a notar o preocuparse mucho por los 38 MB que faltan.

+0

Si veo 40 megas utilizados después de escribir un solo módulo y aplicación tendrá ... digamos 20 - 30 de estos módulos se multiplican conjunto completo de datos que, bueno - Me preocupa que no voy a hacer en 512 megabytes de RAM – PiotrK

+1

@ PiotrK: Sí, si fuera así de simple, pero no lo es. Las aplicaciones .NET son administradas por el tiempo de ejecución. La cantidad de memoria utilizada no refleja directamente lo que está haciendo con su código, sus suposiciones son incorrectas. –

+0

PiotrK: pero no lo harás. El uso de memoria no escala linealmente con el número o tamaño de los módulos. Recibes un gran golpe para el tiempo de ejecución de .NET, pero solo recibes ese golpe una vez. Es posible que vea que con un módulo consume 40 MB, pero cada módulo posterior puede agregar solo otro par de MB (dependiendo de la cantidad de memoria que asigna, por supuesto). – itowlson

-8

Haciendo un rápido Calc es probable que esté asignando alrededor de 340K objetos (restando la c12MB golpe habitual para aplicaciones de consola individuales en 32 bits, uff Steve!) Y ver [la eliminación de la referencia a un escenario típico de comer 8 bytes por objeto + entonces algunos para otros sospechosos habituales] de tiempo de ejecución y desperdicio de System.Object para tipos de referencia por el tiempo de autonomía inflado copyright @ Sun.com ...

Pruebe y diseñe para tipos/estructuras de valor si es posible ... si no puede, difícil, dígales a sus usuarios que no deben ejecutar más de 10 aplicaciones .NET o que su máquina se sentirá más lenta que C64. Si te hace sentir mejor, prueba con WPF o Silverlight y siente c100MB de penalización por unos pocos botones y animaciones llamativas.

(sensación downvote)

+2

Este es un consejo terrible e inexacto. -1 –

+4

Tan mal que tengo que decirlo dos veces. –

+0

Claro, asegúrese de saltar a los diseñadores de motores de ejecución CLR blog y leer las entradas de por qué se optó por la técnica de tipo de valor, en realidad asignación de matriz para que puedan evitar este tipo de sobrecarga en la friolera de 2 aplicaciones se dieron cuenta desde el año 2001. Por cierto , en ese equipo, la mayoría fueron hechas, se escapó, Google nodriza y cada vez se allanando el camino .. –

0

Si está utilizando el Administrador de tareas para mirar a la memoria que puede ser engañoso. Working Set es la cantidad de memoria virtual asignada al proceso. No necesariamente cuánto usa la aplicación; esto es especialmente cierto en el entorno recolectado de basura de .NET. A medida que su programa asigna memoria, .NET CLR/GC generalmente solicitará más memoria de la que realmente necesita del SO para que pueda asignar de manera eficiente esa memoria a los objetos administrados en su programa en el futuro.

Una manera rápida y sucia (muy sucio) para ver si esto está afectando a sus usuarios es establecer Process.MaxWorkingSet propiedad a 0. Esto es similar al uso de SetProcessWorkingSetSize en Win32 para tratar de recortar la cantidad de páginas asociadas al proceso. Si ve inmediatamente una caída en el uso de la memoria, entonces sabrá lo que está sucediendo. Sin embargo, tan pronto como empiece a asignar memoria nuevamente a través del GC/CLR, volverá a subir, y generalmente eso es algo bueno. Realmente no deberías preocuparte por eso y darle al GC la oportunidad de hacerlo de la manera correcta.

Para optimizar el uso de memoria tanto de su programa y tener una mejor idea de cómo funciona la asignación de memoria en el CLR Le sugiero que comience a jugar con dotTrace (mi preferencia), Ants Profiler (que por cierto publishes a cool video on this topic here). CLRProfiler es interesante también, pero está un poco anticuado en estos días, pero es gratis.

Cuestiones relacionadas