¿Cuándo se libera la memoria asignada por el proceso .NET a Windows?

La puesta en marcha

.NET asigna memoria para el montón de cada generación (0, 1, 2, LOH) en segmentos para obtener un bloque continuo de memoria, al inicio y cuando intenta satisfacer una solicitud de asignación, después de una recostackción.

Esta memoria asignada para cada stack probablemente se nivelará a medida que la aplicación “se caliente”, excepto potencialmente para la generación 2 y el gran montón de objetos. Durante una recolección de basura, cada montón (0, 1, 2) se barre y se compacta, excepto para el montón de objetos grandes (LOH), que simplemente se barre.

Entiendo que la parte de ‘barrido’ de una colección significa que el GC identifica qué objetos ya no están enraizados y están disponibles para recostackción (o finalización) y que ‘compacto’ significa que las direcciones que todavía están vivas en un montón se reorganizan para que el montón restante disponible tenga más memoria continua disponible para él.

A medida que se exceda el presupuesto para cada segmento dentro del montón, .NET asignará otro segmento para cumplir con las asignaciones si es posible.

La pregunta

Mi pregunta se reduce a lo que le sucede a esa memoria en cada montón, que ya no es utilizada por la aplicación (comprometida), pero que todavía está reservada por .NET. ¿Cuándo se devuelve al sistema operativo? .

Creo que este es el escenario donde parece que un proceso consume mucha memoria (el tamaño virtual es bastante grande, pero los bytes privados son pequeños), pero cuando se inspeccionan sus montones son en su mayoría de espacio libre . Como otra advertencia, el tamaño total de los montones también puede ser bastante pequeño y no tiene en cuenta la memoria que consume el proceso.

No hay un finalizador bloqueado y todo se ve saludable para un proceso: puede haber estado funcionando durante semanas antes de que activara una alerta de monitor (por ejemplo).

Para mayor aclaración de la pregunta, si lee Tess .NET Memory Management – A Restaurant Analogy , si las mesas son segmentos de montón, ¿el restaurante pierde tablas alguna vez (p. Ej., Segmentos de montón gratuitos)?

Editar

  1. Se eliminó la referencia confusa al conjunto de trabajo y los pollos
  2. Se agregó una referencia a la analogía del restaurante Tess

Mi respuesta es: no importa. El SO le da a la aplicación (dentro de la cual se ejecuta el tiempo de ejecución .NET) memoria virtual . Esta no es memoria “real”. El sistema operativo puede colocar cada página de memoria virtual donde quiera: en el procesador, en la memoria principal, en el disco. Por lo tanto, es posible que una aplicación use más memoria que la cantidad de RAM en el sistema, y ​​el sistema operativo copiará los bits que se necesitan para / desde el disco para garantizar que la aplicación siga ejecutándose (ciertas limitaciones técnicas y de direccionamiento).

El SO maneja la memoria virtual de todos los procesos en el sistema, y ​​asegura que un progtwig no acapare toda la RAM en el sistema en detrimento de otros progtwigs. Cuando el tiempo de ejecución de .NET solicita memoria del sistema para su uso en los montones, pero luego no la utiliza, esta memoria (si el sistema tiene poca RAM libre) se moverá al disco, porque no se está accediendo .

Aclaración por correo electrónico de Tess : (el énfasis es mío)

Los tamaños de segmento permanecen iguales durante el transcurso de la aplicación, pero hay dos cosas a considerar aquí.

  1. Las asignaciones para un segmento son una asignación virtual , lo que significa que mientras reservamos la memoria virtual , solo comprometemos lo que realmente usamos, por lo que los bytes privados utilizados para un segmento no son iguales al tamaño del segmento, esto significa que después de un GC, tus bytes privados bajarán, mientras que tus bytes virtuales permanecerán iguales.

  2. Cuando un segmento ya no se utiliza, es decir, si GC todo en un segmento para que ya no contenga ningún objeto .net, la asignación virtual se devuelve al sistema operativo.

Teniendo eso en cuenta, los segmentos de montón (mesas de restaurante) serán devueltos al sistema operativo.

No sé la respuesta a esto, pero sospecho que .NET no libera sus montones hasta que el proceso finalice (y posiblemente al descargar un AppDomain, supongo). Esto solo se basa en mi observación de los contadores de memoria .NET de perfmon. Los contadores de bytes totales de GC muestran, al menos en mi aplicación, que los bytes reservados suben y bajan un poco durante la vida útil de mi aplicación, como unos 30 MB.

Y, si el GC se está ejecutando en el modo de servidor, quizás .NET libera memoria más a menudo.