Opérations sur la mémoire virtuelle

Ce forum est dédié à apprendre le développement de programmes user mode sur Linux

Moderator: Rick

Post Reply
Hydraxx
Site Admin
Posts: 114
Joined: Mon Jan 12, 2026 4:04 pm
Location: France
Contact:

Opérations sur la mémoire virtuelle

Post by Hydraxx »

Opérations sur la mémoire virtuelle

Résumé — Ce qu’il faut retenir

Ce chapitre présente plusieurs appels système qui permettent de contrôler plus finement des régions de l’espace d’adressage virtuel d’un processus.
  • Code: Select all

    mprotect()
    modifie les permissions d’accès d’une région mémoire déjà mappée.
  • Code: Select all

    mlock()
    verrouille des pages en RAM afin d’éviter qu’elles soient évincées vers le swap.
  • Code: Select all

    munlock()
    retire ce verrouillage.
  • Code: Select all

    mlockall()
    verrouille tout ou partie de l’espace mémoire du processus.
  • Code: Select all

    munlockall()
    retire les verrouillages établis par

    Code: Select all

    mlockall()
    .
  • Code: Select all

    mincore()
    permet de savoir quelles pages d’une région sont actuellement résidentes en mémoire physique.
  • Code: Select all

    madvise()
    permet d’indiquer au noyau la manière dont une région mémoire devrait probablement être utilisée.
Ces fonctions ne servent pas uniquement à l’IPC. Elles peuvent être utilisées sur de nombreuses régions de mémoire virtuelle, notamment celles créées avec

Code: Select all

mmap()
.

1. Modifier les protections mémoire avec mprotect()

Prototype

Code: Select all

#include <sys/mman.h>

int mprotect(void *addr, size_t len, int prot);
Rôle

Code: Select all

mprotect()
modifie les droits d’accès appliqués aux pages de mémoire virtuelle couvrant l’intervalle commençant à

Code: Select all

addr
sur

Code: Select all

len
octets.

La région doit déjà appartenir à l’espace d’adressage du processus.

Sur Linux,

Code: Select all

addr
doit normalement être alignée sur une frontière de page.

La taille

Code: Select all

len
peut ne pas être un multiple de la taille d’une page : les pages concernées sont traitées comme des pages complètes.

Pour connaître la taille d’une page :

Code: Select all

long page_size = sysconf(_SC_PAGESIZE);
ou :

Code: Select all

long page_size = sysconf(_SC_PAGE_SIZE);
Valeurs possibles de prot

Code: Select all

PROT_NONE
Aucun accès autorisé.

Code: Select all

PROT_READ
Lecture autorisée.

Code: Select all

PROT_WRITE
Écriture autorisée.

Code: Select all

PROT_EXEC
Exécution autorisée.

Ces flags peuvent être combinés avec l’opérateur binaire :

Code: Select all

|
Exemple :

Code: Select all

PROT_READ | PROT_WRITE
Valeur de retour
Exemple simple

Code: Select all

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

int main(void)
{
    long page_size = sysconf(_SC_PAGESIZE);

    void *mem = mmap(
        NULL,
        page_size,
        PROT_NONE,
        MAP_PRIVATE | MAP_ANONYMOUS,
        -1,
        0
    );

    if (mem == MAP_FAILED) {
        perror("mmap");
        return EXIT_FAILURE;
    }

    if (mprotect(mem, page_size, PROT_READ | PROT_WRITE) == -1) {
        perror("mprotect");
        munmap(mem, page_size);
        return EXIT_FAILURE;
    }

    ((char *)mem)[0] = 'A';

    printf("%c\n", ((char *)mem)[0]);

    munmap(mem, page_size);
    return EXIT_SUCCESS;
}
Ici :
  • la région est créée avec

    Code: Select all

    PROT_NONE
    ;
  • tout accès est initialement interdit ;
  • Code: Select all

    mprotect()
    ajoute ensuite

    Code: Select all

    PROT_READ | PROT_WRITE
    ;
  • le programme peut alors lire et écrire dans cette région.
Pourquoi c’est utile ?
  • créer des pages gardes ;
  • empêcher temporairement l’écriture dans une région ;
  • passer une zone en lecture seule ;
  • rendre une zone exécutable ou non exécutable ;
  • implémenter certains allocateurs mémoire ;
  • protéger des données sensibles ;
  • détecter des dépassements mémoire ;
  • modifier les permissions d’un mapping créé par

    Code: Select all

    mmap()
    .
Attention

Une tentative d’accès incompatible avec les protections d’une page peut provoquer un signal tel que :

Code: Select all

SIGSEGV
Exemple :

Code: Select all

mprotect(mem, page_size, PROT_NONE);
Puis :

Code: Select all

char c = *((char *)mem);
peut provoquer un :

Code: Select all

SIGSEGV
2. Verrouiller des pages en mémoire avec mlock()

Prototype

Code: Select all

#include <sys/mman.h>

int mlock(const void *addr, size_t len);
Rôle

Code: Select all

mlock()
demande au noyau de maintenir les pages couvrant une région mémoire en mémoire physique.

Ces pages ne doivent normalement pas être évincées vers le swap tant qu’elles restent verrouillées.

Contrairement à

Code: Select all

mprotect()
, l’adresse fournie à

Code: Select all

mlock()
n’a généralement pas besoin d’être elle-même alignée sur une page.

Le noyau verrouille les pages complètes qui intersectent la région demandée.

Pourquoi verrouiller une région ?
  • éviter une latence causée par un défaut de page ;
  • garder certaines données immédiatement accessibles ;
  • réduire le risque qu’une donnée sensible se retrouve dans le swap ;
  • répondre aux contraintes de certains programmes temps réel ;
  • garder certaines pages critiques résidentes.
Exemple :

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

int main(void)
{
    long page_size = sysconf(_SC_PAGESIZE);

    void *mem = mmap(
        NULL,
        page_size,
        PROT_READ | PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS,
        -1,
        0
    );

    if (mem == MAP_FAILED) {
        perror("mmap");
        return EXIT_FAILURE;
    }

    if (mlock(mem, page_size) == -1) {
        perror("mlock");
    }

    ((char *)mem)[0] = 'X';

    munlock(mem, page_size);
    munmap(mem, page_size);

    return EXIT_SUCCESS;
}
Valeur de retour
3. RLIMIT_MEMLOCK

Linux limite la quantité de mémoire qu’un processus non privilégié peut verrouiller.

Cette limite peut être consultée ou modifiée avec :

Code: Select all

getrlimit()
et :

Code: Select all

setrlimit()
La ressource concernée est :

Code: Select all

RLIMIT_MEMLOCK
Exemple :

Code: Select all

#include <stdio.h>
#include <sys/resource.h>

int main(void)
{
    struct rlimit lim;

    if (getrlimit(RLIMIT_MEMLOCK, &lim) == -1) {
        perror("getrlimit");
        return 1;
    }

    printf("soft = %llu\n",
           (unsigned long long)lim.rlim_cur);

    printf("hard = %llu\n",
           (unsigned long long)lim.rlim_max);

    return 0;
}
Important
  • la limite souple est dans

    Code: Select all

    rlim_cur
    ;
  • la limite maximale est dans

    Code: Select all

    rlim_max
    ;
  • un processus non privilégié ne peut normalement pas dépasser sa limite ;
  • la quantité de mémoire verrouillée est comptabilisée par pages.
Privilièges

Sur Linux, certaines limitations peuvent être levées ou étendues pour les processus possédant les capacités appropriées.

Une capacité souvent liée au verrouillage mémoire est :

Code: Select all

CAP_IPC_LOCK
4. Déverrouiller des pages avec munlock()

Prototype

Code: Select all

#include <sys/mman.h>

int munlock(const void *addr, size_t len);
Rôle

Code: Select all

munlock()
retire le verrouillage établi sur les pages d’une région.

Cela ne signifie pas que les pages sont immédiatement supprimées de la RAM.

Cela signifie simplement qu’elles peuvent à nouveau être évincées si le noyau en a besoin.

Exemple :

Code: Select all

mlock(mem, size);

/* travail */

munlock(mem, size);
Point important

Le verrouillage concerne les pages virtuelles de la région, pas uniquement le contenu logique que le programme considère comme « utile ».

Deux appels portant sur des intervalles qui se recouvrent peuvent donc concerner les mêmes pages physiques.

5. Verrouiller l’espace mémoire avec mlockall()

Prototype

Code: Select all

#include <sys/mman.h>

int mlockall(int flags);
Flags principaux

Code: Select all

MCL_CURRENT
Verrouille les pages actuellement mappées dans l’espace virtuel du processus.

Code: Select all

MCL_FUTURE
Demande également que les futures pages mappées dans le processus soient verrouillées.

Les deux peuvent être combinés :

Code: Select all

MCL_CURRENT | MCL_FUTURE
Exemple :

Code: Select all

#include <stdio.h>
#include <sys/mman.h>

int main(void)
{
    if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
        perror("mlockall");
        return 1;
    }

    /* code critique */

    munlockall();

    return 0;
}
Conséquence de MCL_FUTURE

Si le processus atteint sa limite de mémoire verrouillable, certaines opérations futures susceptibles d’augmenter son espace mémoire peuvent échouer.

Cela peut concerner par exemple :

Code: Select all

mmap()
ou une croissance de pile nécessitant de nouvelles pages.

6. munlockall()

Prototype

Code: Select all

#include <sys/mman.h>

int munlockall(void);
Rôle

Code: Select all

munlockall()
retire les verrouillages appliqués aux pages du processus.

Valeur de retour :
Quand les verrouillages disparaissent-ils ?

Les verrous mémoire sont également retirés lorsque les pages ne font plus partie de l’espace d’adressage du processus.

Par exemple après :

Code: Select all

munmap()
ou à la terminaison du processus.

7. Sémantique importante du verrouillage mémoire

Le verrouillage est appliqué par pages.

Supposons une taille de page de :

Code: Select all

4096
octets.

Si l’on verrouille une petite zone située au milieu d’une page :

Code: Select all

mlock(ptr + 100, 20);
le noyau doit en pratique considérer la page contenant cette zone.

Même si la demande ne porte que sur quelques octets, le verrouillage mémoire agit à la granularité des pages.

Autre point important

Le verrouillage n’est pas un mécanisme d’exclusion mutuelle.

Code: Select all

mlock()
ne remplace pas :

Code: Select all

pthread_mutex_lock()
ni un sémaphore.

Il empêche l’éviction des pages, mais n’empêche pas plusieurs threads ou processus d’accéder simultanément aux données.

8. Savoir si des pages sont résidentes avec mincore()

Prototype

Code: Select all

#define _DEFAULT_SOURCE
#include <sys/mman.h>

int mincore(void *addr, size_t length, unsigned char *vec);
Rôle

Code: Select all

mincore()
indique quelles pages d’une région virtuelle sont actuellement résidentes en RAM.

Elle ne verrouille rien.

Elle ne charge pas nécessairement les pages.

Elle fournit seulement un état de résidence au moment de l’appel.

Contraintes

L’adresse :

Code: Select all

addr
doit être alignée sur une frontière de page.

Le tableau :

Code: Select all

vec
doit contenir au moins un octet par page de la région.

Nombre de pages :

Code: Select all

pages = (length + page_size - 1) / page_size;
Exemple d’allocation :

Code: Select all

unsigned char *vec = calloc(pages, sizeof(unsigned char));
Interprétation du tableau

Pour chaque page, le bit de poids faible indique si la page est résidente.

Test typique :

Code: Select all

if (vec[i] & 1) {
    printf("page presente en RAM\n");
}
Sinon :

Code: Select all

printf("page non residente\n");
Exemple complet

Code: Select all

#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>

int main(void)
{
    long page_size = sysconf(_SC_PAGESIZE);
    size_t size = (size_t)page_size * 4;

    char *mem = mmap(
        NULL,
        size,
        PROT_READ | PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS,
        -1,
        0
    );

    if (mem == MAP_FAILED) {
        perror("mmap");
        return EXIT_FAILURE;
    }

    size_t pages = size / (size_t)page_size;

    unsigned char *vec = calloc(pages, sizeof(unsigned char));

    if (vec == NULL) {
        perror("calloc");
        munmap(mem, size);
        return EXIT_FAILURE;
    }

    if (mincore(mem, size, vec) == -1) {
        perror("mincore");
        free(vec);
        munmap(mem, size);
        return EXIT_FAILURE;
    }

    for (size_t i = 0; i < pages; i++) {
        printf(
            "page %zu : %s\n",
            i,
            (vec[i] & 1) ? "residente" : "non residente"
        );
    }

    free(vec);
    munmap(mem, size);

    return EXIT_SUCCESS;
}
Pourquoi certaines pages ne sont-elles pas immédiatement présentes ?

Parce que Linux utilise largement la pagination à la demande.

Un mapping peut exister dans l’espace virtuel sans que toutes ses pages aient déjà reçu une page physique.

Une page est souvent matérialisée lors du premier accès.

Expérience simple

Créer un mapping :

Code: Select all

char *mem = mmap(...);
Puis consulter :

Code: Select all

mincore()
Ensuite toucher certaines pages :

Code: Select all

mem[0] = 1;
mem[page_size] = 2;
Puis refaire :

Code: Select all

mincore()
On peut constater que les pages accédées ont davantage de chances d’être résidentes.

9. Conseiller le noyau avec madvise()

Prototype

Code: Select all

#define _DEFAULT_SOURCE
#include <sys/mman.h>

int madvise(void *addr, size_t length, int advice);
Rôle

Code: Select all

madvise()
permet au programme d’indiquer au noyau la manière dont il prévoit d’utiliser une région mémoire.

Il s’agit d’un conseil.

Le noyau peut utiliser cette information pour optimiser notamment :
  • le read-ahead ;
  • la mise en cache ;
  • la pagination ;
  • la récupération de pages ;
  • le comportement de certaines régions mappées.
Valeurs classiques de advice

Code: Select all

MADV_NORMAL
Comportement normal.

C’est le comportement par défaut.

Code: Select all

MADV_RANDOM
Le programme prévoit des accès aléatoires.

Le noyau peut réduire ou désactiver certaines stratégies de lecture anticipée.

Code: Select all

MADV_SEQUENTIAL
Le programme prévoit de parcourir les pages séquentiellement.

Le noyau peut adapter son read-ahead et recycler plus rapidement certaines pages déjà parcourues.

Code: Select all

MADV_WILLNEED
Le programme indique qu’il prévoit d’utiliser prochainement les pages.

Le noyau peut essayer de préparer les données afin de réduire les futurs défauts de page.

Code: Select all

MADV_DONTNEED
Le programme indique qu’il n’a plus besoin immédiatement du contenu de ces pages.

La sémantique exacte dépend du type de mapping et du système.

Sur Linux, ce conseil peut permettre au noyau de libérer certaines pages et de les recharger ou recréer ultérieurement si elles sont accédées à nouveau.

Exemple MADV_SEQUENTIAL

Code: Select all

if (madvise(mem, size, MADV_SEQUENTIAL) == -1) {
    perror("madvise");
}
Utilisation typique :
  • gros fichier parcouru du début à la fin ;
  • scan séquentiel d’une base de données ;
  • analyse linéaire d’un mapping.
Exemple MADV_RANDOM

Code: Select all

if (madvise(mem, size, MADV_RANDOM) == -1) {
    perror("madvise");
}
Utilisation typique :
  • index ;
  • table de hachage mappée ;
  • base de données avec lectures non séquentielles ;
  • accès pseudo-aléatoires dans un fichier.
Exemple MADV_WILLNEED

Code: Select all

if (madvise(mem, size, MADV_WILLNEED) == -1) {
    perror("madvise");
}
Le but est d’indiquer au noyau :

Code: Select all

"Je vais probablement avoir besoin de ces pages prochainement."
Exemple MADV_DONTNEED

Code: Select all

if (madvise(mem, size, MADV_DONTNEED) == -1) {
    perror("madvise");
}
Le programme indique essentiellement que les pages n’ont plus besoin d’être conservées comme avant.

Il ne faut cependant pas interpréter cela comme un équivalent direct de :

Code: Select all

free()
ou :

Code: Select all

munmap()
La région virtuelle reste mappée.

10. Différence entre madvise(), mincore(), mlock() et mprotect()

Code: Select all

mprotect()
agit sur les permissions.

Question :

Code: Select all

Qui peut lire, écrire ou exécuter cette mémoire ?

Code: Select all

mlock()
agit sur la résidence.

Question :

Code: Select all

Puis-je empêcher ces pages d'être évincées ?

Code: Select all

mincore()
observe la résidence.

Question :

Code: Select all

Ces pages sont-elles actuellement présentes en RAM ?

Code: Select all

madvise()
donne un conseil d’utilisation au noyau.

Question :

Code: Select all

Comment vais-je probablement utiliser ces pages ?
11. Différence entre mlock() et mmap()

Code: Select all

mmap()
crée ou établit un mapping dans l’espace virtuel.

Code: Select all

mlock()
agit sur une région qui existe déjà afin d’essayer de maintenir ses pages en RAM.

On peut donc avoir :

Code: Select all

mmap()
sans :

Code: Select all

mlock()
et c’est de loin le cas le plus courant.

Exemple logique :

Code: Select all

mmap()
   |
   +--> région virtuelle créée
            |
            +--> mprotect() : changer les permissions
            |
            +--> mlock()    : verrouiller en RAM
            |
            +--> mincore()  : vérifier la résidence
            |
            +--> madvise()  : donner un conseil au noyau
            |
            +--> munmap()   : supprimer le mapping
12. Défauts de page et résidence mémoire

Une adresse virtuelle peut être valide sans que la page correspondante soit immédiatement présente en RAM.

Lorsqu’un thread accède à une page absente, le processeur déclenche un défaut de page.

Le noyau détermine alors si l’accès est valide.

Si l’accès est valide, il peut :
  • attribuer une page physique ;
  • charger des données depuis un fichier ;
  • restaurer une page ;
  • mettre à jour les tables de pages ;
  • reprendre l’exécution du thread.
Si l’accès est invalide, le processus peut recevoir un signal tel que :

Code: Select all

SIGSEGV
13. mmap(), mprotect() et pages

Exemple :

Code: Select all

void *p = mmap(
    NULL,
    4096,
    PROT_READ | PROT_WRITE,
    MAP_PRIVATE | MAP_ANONYMOUS,
    -1,
    0
);
Le noyau réserve une région virtuelle.

Les permissions sont alors :

Code: Select all

READ
WRITE
On peut ensuite faire :

Code: Select all

mprotect(p, 4096, PROT_READ);
La région devient en pratique :

Code: Select all

READ
Une écriture ultérieure :

Code: Select all

((char *)p)[0] = 'X';
peut provoquer :

Code: Select all

SIGSEGV
14. Exemple combiné

Code: Select all

#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    long page_size = sysconf(_SC_PAGESIZE);
    size_t size = (size_t)page_size * 2;

    char *mem = mmap(
        NULL,
        size,
        PROT_READ | PROT_WRITE,
        MAP_PRIVATE | MAP_ANONYMOUS,
        -1,
        0
    );

    if (mem == MAP_FAILED) {
        perror("mmap");
        return EXIT_FAILURE;
    }

    strcpy(mem, "Inside The System");

    if (mlock(mem, size) == -1) {
        perror("mlock");
    }

    if (madvise(mem, size, MADV_SEQUENTIAL) == -1) {
        perror("madvise");
    }

    size_t pages = size / (size_t)page_size;

    unsigned char *vec = calloc(pages, sizeof(unsigned char));

    if (vec != NULL) {
        if (mincore(mem, size, vec) == 0) {
            for (size_t i = 0; i < pages; i++) {
                printf(
                    "page %zu : %s\n",
                    i,
                    (vec[i] & 1) ? "RAM" : "non residente"
                );
            }
        }

        free(vec);
    }

    if (mprotect(mem, size, PROT_READ) == -1) {
        perror("mprotect");
    }

    printf("%s\n", mem);

    munlock(mem, size);
    munmap(mem, size);

    return EXIT_SUCCESS;
}
Cet exemple combine les principales API du chapitre :
  • Code: Select all

    mmap()
    crée le mapping ;
  • Code: Select all

    mlock()
    tente de maintenir ses pages en RAM ;
  • Code: Select all

    madvise()
    fournit un conseil d’utilisation ;
  • Code: Select all

    mincore()
    consulte la résidence des pages ;
  • Code: Select all

    mprotect()
    passe ensuite le mapping en lecture seule ;
  • Code: Select all

    munlock()
    retire le verrouillage ;
  • Code: Select all

    munmap()
    détruit le mapping.
15. Erreurs à connaître

mprotect()

Peut échouer si :
  • l’adresse est mal alignée ;
  • une partie de la région n’est pas mappée ;
  • les permissions demandées sont invalides ;
  • la protection demandée n’est pas autorisée.
mlock()

Peut échouer si :
  • la limite

    Code: Select all

    RLIMIT_MEMLOCK
    est dépassée ;
  • la plage mémoire n’est pas valide ;
  • le processus ne possède pas les privilèges nécessaires.
mincore()

Peut échouer si :
  • Code: Select all

    addr
    n’est pas alignée sur une frontière de page ;
  • la région n’est pas mappée ;
  • les paramètres sont invalides.
madvise()

Peut échouer si :
  • l’adresse ou la plage ne conviennent pas ;
  • le conseil fourni n’est pas reconnu ;
  • le mapping ne supporte pas l’opération demandée.
Toujours vérifier les erreurs avec :

Code: Select all

perror()
ou :

Code: Select all

strerror(errno)
16. Carte mentale

Code: Select all

                  MEMOIRE VIRTUELLE
                         |
        +----------------+----------------+
        |                |                |
   permissions        residence       strategie
        |                |                |
   mprotect()         mlock()          madvise()
                         |
                   munlock()
                         |
                  mlockall()
                         |
                 munlockall()

                   observation
                        |
                    mincore()
17. APIs à retenir absolument

Les fonctions principales à connaître après ce chapitre sont :

Code: Select all

mprotect()

Code: Select all

mlock()

Code: Select all

munlock()

Code: Select all

mlockall()

Code: Select all

munlockall()

Code: Select all

mincore()

Code: Select all

madvise()
Il faut également connaître les constantes principales :

Code: Select all

PROT_NONE
PROT_READ
PROT_WRITE
PROT_EXEC

Code: Select all

MCL_CURRENT
MCL_FUTURE

Code: Select all

MADV_NORMAL
MADV_RANDOM
MADV_SEQUENTIAL
MADV_WILLNEED
MADV_DONTNEED
et la limite :

Code: Select all

RLIMIT_MEMLOCK
18. Ce qu’il faut savoir expliquer sans documentation

Après ce chapitre, tu devrais être capable d’expliquer :
  • la différence entre mémoire virtuelle et mémoire physiquement résidente ;
  • pourquoi une page mappée peut ne pas encore être présente en RAM ;
  • ce qu’est un défaut de page ;
  • pourquoi les opérations mémoire travaillent souvent à la granularité des pages ;
  • comment modifier les permissions d’un mapping avec

    Code: Select all

    mprotect()
    ;
  • comment empêcher des pages d’être évincées avec

    Code: Select all

    mlock()
    ;
  • pourquoi

    Code: Select all

    RLIMIT_MEMLOCK
    existe ;
  • la différence entre

    Code: Select all

    MCL_CURRENT
    et

    Code: Select all

    MCL_FUTURE
    ;
  • comment tester la résidence avec

    Code: Select all

    mincore()
    ;
  • pourquoi

    Code: Select all

    madvise()
    est un conseil et non un ordre absolu ;
  • la différence entre

    Code: Select all

    MADV_RANDOM
    et

    Code: Select all

    MADV_SEQUENTIAL
    ;
  • la différence entre

    Code: Select all

    MADV_WILLNEED
    et

    Code: Select all

    MADV_DONTNEED
    ;
  • pourquoi

    Code: Select all

    munlock()
    ne supprime pas une région mémoire ;
  • pourquoi

    Code: Select all

    munmap()
    et

    Code: Select all

    munlock()
    ne servent pas à la même chose.
19. Mini fiche API

Code: Select all

int mprotect(void *addr, size_t len, int prot);
Modifie les permissions d’une région.

Code: Select all

int mlock(const void *addr, size_t len);
Verrouille les pages d’une région en RAM.

Code: Select all

int munlock(const void *addr, size_t len);
Retire le verrouillage.

Code: Select all

int mlockall(int flags);
Verrouille une partie ou l’ensemble des pages du processus selon les flags.

Code: Select all

int munlockall(void);
Retire les verrouillages globaux.

Code: Select all

int mincore(void *addr, size_t length, unsigned char *vec);
Indique quelles pages sont résidentes.

Code: Select all

int madvise(void *addr, size_t length, int advice);
Informe le noyau du schéma probable d’utilisation de la région.

20. Pièges classiques
  • Confondre

    Code: Select all

    mprotect()
    avec

    Code: Select all

    mlock()
    .
  • Croire que

    Code: Select all

    mlock()
    protège contre les écritures.
  • Croire que

    Code: Select all

    munlock()
    libère la mémoire.
  • Croire que

    Code: Select all

    mincore()
    charge les pages en RAM.
  • Croire que

    Code: Select all

    madvise()
    oblige toujours le noyau à suivre le conseil.
  • Oublier l’alignement de

    Code: Select all

    mprotect()
    et

    Code: Select all

    mincore()
    .
  • Oublier que la mémoire est gérée par pages.
  • Oublier de vérifier

    Code: Select all

    MAP_FAILED
    après

    Code: Select all

    mmap()
    .
  • Oublier de vérifier les retours

    Code: Select all

    -1
    .
  • Oublier

    Code: Select all

    RLIMIT_MEMLOCK
    lors de l’utilisation de

    Code: Select all

    mlock()
    .
Conclusion

Le chapitre 50 complète très bien l’étude de

Code: Select all

mmap()
.

Avec

Code: Select all

mmap()
, on crée une région dans l’espace virtuel.

Avec

Code: Select all

mprotect()
, on contrôle ses permissions.

Avec

Code: Select all

mlock()
et

Code: Select all

mlockall()
, on contrôle son verrouillage en mémoire physique.

Avec

Code: Select all

mincore()
, on observe quelles pages sont résidentes.

Avec

Code: Select all

madvise()
, on informe le noyau de la manière dont on prévoit d’utiliser les pages.

La logique générale à retenir est donc :

Code: Select all

mmap()
    -> creer une region virtuelle

mprotect()
    -> modifier les droits

mlock()
    -> conserver des pages en RAM

mincore()
    -> observer la residence

madvise()
    -> conseiller le noyau

munmap()
    -> supprimer le mapping

Who is online

Users browsing this forum: No registered users and 1 guest