eryksun ha respondido la pregunta n. ° 1, y he respondido la pregunta n. ° 3 (la original n. ° 4), pero ahora respondamos la pregunta n. ° 2:
¿Por qué libera 50.5mb en particular? ¿En qué cantidad se libera?
En lo que se basa es, en última instancia, en toda una serie de coincidencias dentro de Python y malloc
que son muy difíciles de predecir.
Primero, dependiendo de cómo esté midiendo la memoria, es posible que solo esté midiendo páginas realmente asignadas a la memoria. En ese caso, cada vez que el localizador cambia una página, la memoria aparecerá como "liberada", aunque no se haya liberado.
O puede estar midiendo páginas en uso, que pueden o no contar páginas asignadas pero nunca tocadas (en sistemas que se sobreasignan de manera optimista, como Linux), páginas que están asignadas pero etiquetadas MADV_FREE
, etc.
Si realmente está midiendo las páginas asignadas (que en realidad no es algo muy útil, pero parece ser lo que está preguntando), y las páginas realmente se han desasignado, dos circunstancias en las que esto puede suceder: ha usado brk
o equivalente para reducir el segmento de datos (muy raro hoy en día), o ha usado munmap
o similar para liberar un segmento mapeado. (En teoría, también hay una variante menor para este último, ya que hay formas de liberar parte de un segmento mapeado, por ejemplo, robarlo MAP_FIXED
para un MADV_FREE
segmento que inmediatamente desasigne).
Pero la mayoría de los programas no asignan directamente cosas de páginas de memoria; usan un malloc
asignador de estilo. Cuando llama free
, el asignador solo puede liberar páginas al sistema operativo si resulta serfree
el último objeto vivo en una asignación (o en las últimas N páginas del segmento de datos). No hay forma de que su aplicación pueda predecir esto razonablemente, o incluso detectar que sucedió de antemano.
CPython hace que esto sea aún más complicado: tiene un asignador de objetos de 2 niveles personalizado encima de un asignador de memoria personalizado encima malloc
. (Consulte los comentarios de origen para obtener una explicación más detallada). Y además de eso, incluso a nivel de API C, mucho menos Python, ni siquiera controla directamente cuándo se desasignan los objetos de nivel superior.
Entonces, cuando liberas un objeto, ¿cómo sabes si va a liberar memoria al sistema operativo? Bueno, primero debe saber que ha publicado la última referencia (incluidas las referencias internas que no conocía), lo que permite que el GC la desasigne. (A diferencia de otras implementaciones, al menos CPython desasignará un objeto tan pronto como se permita). Esto generalmente desasigna al menos dos cosas en el siguiente nivel hacia abajo (por ejemplo, para una cadena, está liberando el PyString
objeto y el búfer de cadena )
Si lo haces desasignar un objeto, para saber si esto hace que el siguiente nivel hacia abajo para cancelar la asignación de un bloque de almacenamiento de objetos, usted tiene que saber el estado interno del asignador de objeto, así como la forma en que está implementado. (Obviamente, esto no puede suceder a menos que desasigne la última cosa del bloque, e incluso así, puede que no suceda).
Si haces desasignar un bloque de almacenamiento de objetos, para saber si esto provoca una free
llamada, usted tiene que saber el estado interno del asignador PyMem, así como la forma en que está implementado. (Nuevamente, debe desasignar el último bloque en uso dentro de una malloc
región ed, e incluso entonces, puede que no suceda).
Si hace free
una malloc
región ed, para saber si esto causa un munmap
o equivalente (o brk
), debe conocer el estado interno del malloc
, así como también cómo se implementa. Y este, a diferencia de los otros, es altamente específico de la plataforma. (Y, de nuevo, generalmente debe desasignar el último uso malloc
dentro de unmmap
segmento, e incluso entonces, puede que no suceda)
Entonces, si quieres entender por qué se lanzó exactamente 50.5mb, tendrás que rastrearlo de abajo hacia arriba. ¿Por qué malloc
anular el mapa de 50.5mb de páginas cuando realizó esas una o más free
llamadas (probablemente por un poco más de 50.5mb)? Tendría que leer la plataforma malloc
y luego recorrer las diferentes tablas y listas para ver su estado actual. (En algunas plataformas, incluso puede hacer uso de información a nivel del sistema, que es prácticamente imposible de capturar sin hacer una instantánea del sistema para inspeccionar sin conexión, pero afortunadamente esto no suele ser un problema). Y luego tienes que haz lo mismo en los 3 niveles por encima de eso.
Entonces, la única respuesta útil a la pregunta es "Porque".
A menos que esté haciendo un desarrollo de recursos limitados (por ejemplo, incrustado), no tiene motivos para preocuparse por estos detalles.
Y si está haciendo un desarrollo de recursos limitados, conocer estos detalles es inútil; prácticamente tiene que hacer una ejecución final alrededor de todos esos niveles y específicamente mmap
la memoria que necesita a nivel de aplicación (posiblemente con un asignador de zona específico de aplicación simple y bien entendido en el medio).