2010-09-24 7 views
5

J'ai un problème qui a été décrit dans plusieurs threads concernant le mappage de mémoire et une consommation de mémoire croissante sous Linux.Linux Les fichiers mappés en mémoire réservent beaucoup de mémoire physique

Lorsque j'ouvre un fichier de 1 Go sous Linux ou Mac OS X et carte en mémoire à l'aide

me.data_begin = mmap(NULL, capacity(me), prot, MAP_SHARED, me.file.handle, 0); 

et séquentiellement lire la mémoire mappée, mon programme utilise de plus en plus de mémoire physique, bien que je posix_madvise (même appelé plusieurs fois pendant le processus de lecture):

posix_madvise(me.data_begin, capacity(me), MMAP_SEQUENTIAL); 

sans succès. :-(

J'ai essayé:

  • drapeaux différents MMAP_RANDOM, MMAP_DONTNEED, MMAP_NORMAL sans succès
  • posix_fadvise (me.file.handle, 0, capacité (moi), POSIX_FADV_DONTNEED) avant et après l'appel mmap -> pas de succès

Il fonctionne sous Mac OS X !!! quand je combine

posix_madvise(.. MMAP_SEQUENTIAL) 

et

msync(me.data_begin, capacity(me), MS_INVALIDATE). 

La mémoire résidente est inférieure à 16M (I périodiquement appelé msync après 16mio étapes).

Mais sous Linux rien ne fonctionne. Est-ce que quelqu'un a une idée ou une histoire à succès pour mon problème sous Linux?

Cheers, David

+0

Cela peut être pertinent ou non, mais il est utile de savoir: utilisez-vous un système 32 bits ou 64 bits? Savez-vous que vous ne devriez pas convertir un 1GB dans un système 32 bits? (même si vous utilisez un système 64 bits, vous pouvez être préoccupé par la portabilité). – Juliano

+0

Tous les systèmes sont 64 bits (avec des pointeurs et des décalages de fichiers de 64 bits) et je pourrais réussir à mapper des fichiers de 40 Go. Je viens de résumer le problème à 1 Go pour des raisons de reproductibilité. – Dave

+0

@Sven. Il y a des cas où l'utilisation d'un mappage de mémoire est inévitable, par exemple lorsqu'un appel de bibliothèque nécessite une région de mémoire, plutôt qu'un fichier. Votre suggestion n'est donc pas utile et ne répond pas à la question. En ce qui concerne la réponse, apparemment sur Linux MMAP_SEQUENTIAL est à peu près * cassé *. La partie lecture anticipée fonctionne, mais pas la partie récupération de page. Et la seule façon de suggérer à Linux qu'en fait ces pages sont de bons candidats est de démêler la région (et de la cartographier à nouveau). –

Répondre

8

Linux gestion de la mémoire est différent des autres systèmes. Le principe clé est que la mémoire qui n'est pas utilisée est de la mémoire gaspillée. À de nombreux égards, Linux essaie d'optimiser l'utilisation de la mémoire, ce qui entraîne (la plupart du temps) de meilleures performances.

Ce n'est pas que "rien ne fonctionne" dans Linux, mais que son comportement est un peu différent de ce que vous attendez. Lorsque les pages de mémoire sont tirées du fichier mmapped, le système d'exploitation doit décider quelles pages de mémoire physique il va libérer (ou échanger) pour pouvoir l'utiliser. Il cherchera les pages qui sont plus faciles à échanger (ne nécessitent pas d'écriture immédiate sur le disque) et seront moins susceptibles d'être réutilisées.

L'appel madvice() POSIX sert à indiquer au système comment votre application utilisera les pages. Mais comme son nom l'indique, il s'agit d'un conseil afin que le système d'exploitation soit mieux équipé pour prendre des décisions de pagination et d'échange. Ce n'est ni une politique ni un ordre.

Pour démontrer les effets de madvice() sur Linux, j'ai modifié un des exercices que je donne à mes étudiants. Voir le complete source code here. Mon système est 64 bits et dispose de 2 Go de RAM, dont environ 50% est actuellement utilisé. En utilisant le programme pour convertir un fichier de 2 Go, lisez-le séquentiellement et jetez tout. Il signale l'utilisation du RSS tous les 200 Mo est lu.Les résultats sans madvice():

<[email protected]> ~% ./madvtest file.dat n 
    0 :  3 MB 
    200 : 202 MB 
    400 : 402 MB 
    600 : 602 MB 
    800 : 802 MB 
    1000 : 1002 MB 
    1200 : 1066 MB 
    1400 : 1068 MB 
    1600 : 1078 MB 
    1800 : 1113 MB 
    2000 : 1113 MB 

Linux continué à pousser les choses de la mémoire jusqu'à environ 1 Go a été lu. Après cela, il a commencé à faire pression sur le processus lui-même (puisque l'autre 50% de la mémoire était active par les autres processus) et stabilisé jusqu'à la fin du fichier.

Maintenant, avec madvice():

<[email protected]> ~% ./madvtest file.dat y 
    0 :  3 MB 
    200 : 202 MB 
    400 : 402 MB 
    600 : 494 MB 
    800 : 501 MB 
    1000 : 518 MB 
    1200 : 530 MB 
    1400 : 530 MB 
    1600 : 530 MB 
    1800 : 595 MB 
    2000 : 788 MB 

Notez que Linux a décidé d'allouer des pages au processus que jusqu'à ce qu'elle atteigne environ 500 Mo, beaucoup plus tôt que sans madvice(). En effet, après cela, les pages actuellement en mémoire semblaient beaucoup plus précieuses que les pages marquées comme accès séquentiel par ce processus. Il y a un seuil dans le VMM qui définit quand commencer à abandonner les anciennes pages du processus.

Vous pouvez vous demander pourquoi Linux a continué d'allouer des pages jusqu'à environ 500 Mo et ne s'est pas arrêté beaucoup plus tôt, car ils ont été marqués comme accès séquentiel. C'est que soit le système avait suffisamment de pages de mémoire libre de toute façon, ou les autres pages de résidents étaient trop vieux pour rester. Entre garder des pages anciennes en mémoire qui ne semblent plus être utiles, et amener plus de pages pour servir un programme qui tourne maintenant, Linux choisit la deuxième option.

Même s'ils étaient marqués comme accès séquentiel, c'était juste un conseil. L'application peut toujours vouloir revenir à ces pages et les relire. Ou une autre application dans le système. L'appel de madvice() ne dit que ce que l'application elle-même fait, Linux prend en considération l'image plus grande.

+0

Merci Juliano, que 50% de comportement soit intéressant. Je me demande juste pourquoi il n'y a aucun moyen d'imposer Linux pour libérer des pages que je ne relis jamais. Au lieu de cela, il sacrifie les tampons et les caches du système de fichiers. Sur MacOS X sacrifier ces tampons bloque le système jusqu'à ce qu'il soit complètement inutilisable. Mais heureusement, nous pouvons empêcher cela via * msync (... MS_INVALIDATE) * Sur Linux, il semble que ce soit le comportement que vous avez observé avec madvice qui empêche le système de caler. – Dave

+1

@Dave: considérez qu'il ne sert à rien de libérer prématurément ces pages. Linux ne sacrifie pas les caches et les tampons, mais fait exactement cela. Comme vous lisez plus de données à partir du disque, Linux doit les apporter à la mémoire de toute façon. Cela met en cache ce qui a été lu sur le disque, mais au lieu de le comptabiliser comme "cache", il le comptabilise comme faisant partie de la partie du flux RSS du processus qui a mappé ce fichier. Lorsque Linux aura besoin de nouveau de cache, il libèrera les pages mappées à cette application. Vous n'avez pas besoin de vous préoccuper de ça! – Juliano

+0

@Juliano: considérez que MADV_SEQUENTIAL indique spécifiquement au système que les pages ne seront accessibles que par lecture séquentielle une seule fois. Ces pages sont des candidats parfaits pour la récupération.Au lieu de cela, je vois que sur ma boîte, jusqu'à 50% de la mémoire (32 Go dans ce cas) est atteint, le cache de fichiers est en cours de récupération. Et je vois que la performance des autres processus se dégrade, Maintenant, j'ai trouvé un moyen ridicule de forcer Linux à ne pas le faire. En démappant et en mappant le fichier à nouveau, tous les 1 Go ou plus. Ce * DOES * résout le problème et après cela je ne vois pas de dégradation de performance pour d'autres processus. –

Questions connexes