2011-03-09 27 views
42

Estoy usando el perfilador de memoria ANTS de Red Gates para depurar una pérdida de memoria. Me sigue advirtiendo que:Qué causa la fragmentación de la memoria en .NET

La fragmentación de la memoria puede estar causando .NET para reservar demasiada memoria libre.

o

fragmentación de memoria está afectando al tamaño del objeto más grande que se puede asignar

Porque tengo TOC, este problema debe ser resuelto.

¿Cuáles son algunas prácticas de codificación estándar que ayudan a evitar la fragmentación de la memoria. ¿Se puede desfragmentar mediante algunos métodos .NET? ¿Ayudaría?

+6

Sería bueno tener alguna información sobre el tipo de aplicación que es esto. La fragmentación de la memoria ocurriría si deja la memoria fija (o usa funciones de E/S que anclan almacenamientos intermedios de E/S entre bastidores), asignaciones de asignadores nativos (como el asignador de tareas COM) o crea muchos objetos grandes, porque el LOH no se compacta. El recolector de elementos no utilizados de .NET ya compacta las asignaciones dinámicas generacionales, lo que tiene un efecto secundario de desfragmentar el espacio libre. Si eso no está sucediendo, es porque algo impide que los objetos se muevan. –

+28

* Como tengo TOC, este problema debe resolverse. * + 1 solo para este comentario. Aunque me gusta la pregunta, – BrokenGlass

+9

Desinstale las herramientas que le molestan pero que no ofrecen ayuda para diagnosticar el problema.La fragmentación de la memoria es un hecho de la vida, no hay nada que puedas hacer para evitarlo que no sea drásticamente poco práctico. El asignador de montón de baja fragmentación ya es el predeterminado para Vista y superior. Solo es un problema si asigna más de la mitad del espacio de direcciones disponible de todos modos, los cerdos no vuelan. –

Respuesta

9

Ya sabes, dudo un poco del perfilador de memoria aquí. El sistema de administración de memoria en .NET realmente intenta desfragmentar el montón moviendo la memoria (es por eso que necesita fijar la memoria para que se comparta con una DLL externa).

Las grandes asignaciones de memoria tomadas durante períodos de tiempo más largos son propensas a una mayor fragmentación. Si bien es poco probable que las pequeñas solicitudes de memoria efímeras (cortas) causen fragmentación en .NET.

Aquí también hay algo en lo que vale la pena pensar. Con el GC actual de .NET, la memoria asignada cerca en el tiempo, típicamente está espaciada muy cerca en el espacio. Que es lo opuesto a la fragmentación. es decir, debe asignar memoria de la manera en que pretende acceder a ella.

¿Es solo un código administrado o contiene cosas como P/Invoke, memoria no administrada (Marshal.AllocHGlobal) o cosas como GCHandle.Alloc (obj, GCHandleType.Pinned)?

+6

El GC no compacta el montón de objetos grandes, que es donde viven los objetos> 85 KB. Una vez que LOH está fragmentado, no hay forma de desfragmentarlo. –

+0

A partir de .NET 4.5.1m hay una manera de compactar el LOH manualmente, aunque recomendaría encarecidamente que no lo haga porque es un gran golpe de rendimiento para su aplicación. https://blogs.msdn.microsoft.com/mariohewardt/2013/06/26/no-more-memory-fragmentation-on-the-net-large-object-heap/ (de nuevo, recomiendo que no lo haga) –

10

El montón de GC trata las asignaciones de objetos grandes de forma diferente. No los compacta, sino que combina bloques libres adyacentes (como una memoria tradicional no administrada).

Más información aquí: http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

Así que la mejor estrategia con objetos muy grandes es la asignación de una vez y luego aferrarse a ellos y reutilizarlos.

+1

Out de curiosidad, me pregunto por qué los tamaños de objeto LOH no se redondean al siguiente múltiplo de 4096? Parecería que eso facilitaría la compactación en algunos contextos del sistema operativo (simplemente mover punteros de página virtual en lugar de copiar memoria), y también reduciría enormemente la fragmentación. Como los objetos LOH generalmente tienen un mínimo de 85K, la sobrecarga del redondeo hasta 4K sería de 5% o menos. – supercat

6

.NET Framework 4.5.1, tiene la capacidad de compactar de forma explícita el gran montón de objetos (LOH) durante la recolección de elementos no utilizados.

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; 
GC.Collect(); 

Ver más información en GCSettings.LargeObjectHeapCompactionMode

+0

Recomiendo encarecidamente que no sea porque es un gran golpe de rendimiento para su aplicación por 2 razones: 1. consume mucho tiempo 2. borra cualquiera de los algoritmos de patrón de asignación que el GC ha recopilado sobre el vida útil de tu aplicación Mientras su aplicación se está ejecutando, el GC realmente se sintoniza aprendiendo cómo su aplicación asigna memoria. Como tal, se vuelve más eficiente (hasta cierto punto) cuanto más tiempo se ejecuta su aplicación. Cuando ejecuta GC.Collect() (o cualquier sobrecarga), borra todos los datos que el GC ha aprendido, por lo que debe comenzar de nuevo. –

+0

@Dave Black, ¿dónde encontraste esa información? MSDN no contiene información sobre el impacto de la compactación LOH en el algoritmo del patrón de asignación. – 23W

+1

@ 23W, conozco a personas que trabajan en el equipo. –

Cuestiones relacionadas