eryksun a répondu à la question n ° 1, et j'ai répondu à la question n ° 3 (l'original n ° 4), mais répondons maintenant à la question n ° 2:
Pourquoi libère-t-il 50,5 Mo en particulier - sur quoi se base le montant libéré?
Ce sur quoi il est basé est, en fin de compte, toute une série de coïncidences à l'intérieur de Python et malloc
qui sont très difficiles à prévoir.
Premièrement, selon la façon dont vous mesurez la mémoire, vous ne mesurerez peut-être que des pages réellement mappées en mémoire. Dans ce cas, à chaque fois qu'une page est permutée par le pager, la mémoire apparaîtra comme "libérée", même si elle n'a pas été libérée.
Ou vous pouvez mesurer les pages en cours d'utilisation, qui peuvent ou non compter les pages allouées mais jamais touchées (sur des systèmes qui surallouent de manière optimiste, comme Linux), les pages qui sont allouées mais balisées MADV_FREE
, etc.
Si vous mesurez vraiment les pages allouées (ce qui n'est en fait pas une chose très utile à faire, mais cela semble être ce que vous demandez), et que les pages ont vraiment été désallouées, deux circonstances dans lesquelles cela peut arriver: Soit vous ' brk
vous avez utilisé ou équivalent pour réduire le segment de données (très rare de nos jours), ou vous avez utilisé munmap
ou similaire pour libérer un segment mappé. (Il existe également en théorie une variante mineure de ce dernier, en ce sens qu'il existe des moyens de libérer une partie d'un segment mappé - par exemple, la voler avec MAP_FIXED
pour un MADV_FREE
segment que vous démappez immédiatement.)
Mais la plupart des programmes n'allouent pas directement les choses à partir des pages de mémoire; ils utilisent un malloc
allocateur de style. Lorsque vous appelez free
, l'allocateur ne peut libérer des pages sur le système d'exploitation que si vous êtes simplement free
le dernier objet actif d'un mappage (ou dans les N dernières pages du segment de données). Il n'y a aucun moyen pour votre application de prévoir raisonnablement cela, ni même de détecter que cela s'est produit à l'avance.
CPython rend cela encore plus compliqué: il a un allocateur d'objet personnalisé à 2 niveaux au-dessus d'un allocateur de mémoire personnalisé malloc
. (Voir les commentaires source pour une explication plus détaillée.) Et en plus de cela, même au niveau de l'API C, encore moins Python, vous ne contrôlez même pas directement le moment où les objets de niveau supérieur sont désalloués.
Alors, lorsque vous libérez un objet, comment savoir s'il va libérer de la mémoire dans le système d'exploitation? Eh bien, vous devez d'abord savoir que vous avez publié la dernière référence (y compris toutes les références internes que vous ne connaissiez pas), permettant au GC de la désallouer. (Contrairement à d'autres implémentations, au moins CPython désallouera un objet dès qu'il est autorisé à le faire.) Cela désalloue généralement au moins deux choses au niveau suivant (par exemple, pour une chaîne, vous libérez l' PyString
objet et le tampon de chaîne ).
Si vous faites désallouer un objet, à savoir si cela provoque le niveau suivant de désaffecter un bloc de stockage d'objets, vous devez connaître l'état interne de l'allocateur d'objet, ainsi que la façon dont il est mis en œuvre. (Cela ne peut évidemment pas arriver à moins que vous ne désallouiez la dernière chose du bloc, et même dans ce cas, cela peut ne pas arriver.)
Si vous faites désallouer un bloc de stockage d'objets, de savoir si cela provoque un free
appel, vous devez connaître l'état interne de l'allocateur PyMem, ainsi que la façon dont il est mis en œuvre. (Encore une fois, vous devez désallouer le dernier bloc utilisé dans une malloc
région ed, et même dans ce cas, cela peut ne pas arriver.)
Si vous faites free
une malloc
région ed, pour savoir si cela provoque un munmap
ou équivalent (ou brk
), vous devez connaître l'état interne du malloc
, ainsi que comment il est implémenté. Et celui-ci, contrairement aux autres, est très spécifique à la plate-forme. (Et encore une fois, vous devez généralement désallouer le dernier en cours d'utilisation malloc
dans un mmap
segment, et même dans ce cas, cela peut ne pas arriver.)
Donc, si vous voulez comprendre pourquoi il est arrivé à libérer exactement 50,5 Mo, vous allez devoir le retracer de bas en haut. Pourquoi malloc
avez-vous démappé 50,5 Mo de pages lorsque vous avez effectué ces un ou plusieurs free
appels (probablement un peu plus de 50,5 Mo)? Vous devrez lire votre plate-forme malloc
, puis parcourir les différents tableaux et listes pour voir son état actuel. (Sur certaines plates-formes, il peut même utiliser des informations au niveau du système, ce qui est pratiquement impossible à capturer sans faire un instantané du système à inspecter hors ligne, mais heureusement, ce n'est généralement pas un problème.) Et puis vous devez faites la même chose aux 3 niveaux supérieurs.
Donc, la seule réponse utile à la question est «Parce que».
À moins que vous ne fassiez du développement à ressources limitées (par exemple, intégrées), vous n'avez aucune raison de vous soucier de ces détails.
Et si vous êtes en train de faire le développement des ressources limitées, sachant que ces détails ne sert à rien; vous devez pratiquement faire une analyse finale autour de tous ces niveaux et plus particulièrement de mmap
la mémoire dont vous avez besoin au niveau de l'application (éventuellement avec un allocateur de zone simple, bien compris et spécifique à l'application entre les deux).