Fichiers mappés en mémoire

Un fichier mappé en mémoire comporte le contenu d'un fichier en mémoire virtuelle. Ce mappage entre un fichier et un espace mémoire permet à une application, y compris les processus multiples, de modifier le fichier en lisant et en écrivant directement dans la mémoire. Depuis .NET Framework version 4, il est possible d'utiliser du code managé pour accéder aux fichiers mappés en mémoire de la même façon que les fonctions Windows natives accèdent aux fichiers mappés en mémoire, comme décrit dans Gestion des fichiers mappés en mémoire dans Win32 (page éventuellement en anglais) dans MSDN Library.

Il existe deux types de fichiers mappés en mémoire :

  • Fichiers mappés en mémoire persistants

    Les fichiers persistants sont des fichiers mappés en mémoire associés à un fichier source sur un disque. Lorsque le dernier processus a terminé d'utiliser le fichier, les données sont enregistrées dans le fichier source sur le disque. Ces fichiers mappés en mémoire conviennent à l'utilisation de fichiers sources extrêmement volumineux.

  • Fichiers mappés en mémoire non persistants

    Les fichiers non persistants sont des fichiers mappés en mémoire qui ne sont pas associés à un fichier source sur un disque. Lorsque le dernier processus a terminé d'utiliser le fichier, les données sont perdues et le fichier est récupéré par l'opération de nettoyage de la mémoire. Ces fichiers conviennent à la création d'une mémoire partagée pour des communications entre processus.

Processus, vues, et gestion de mémoire

Les fichiers mappés en mémoire peuvent être partagés entre plusieurs processus. Les processus peuvent être mappés vers le même fichier mappé en mémoire à l'aide d'un nom commun assigné par le processus qui a créé le fichier.

Pour utiliser un fichier mappé en mémoire, vous devez créer une vue du fichier dans son entier ou partiel. Vous pouvez également créer plusieurs vues pour une même partie du fichier mappé en mémoire, ce qui crée une mémoire à accès concurrentiel. Pour que deux vues restent simultanées, elles doivent être créées à partir du même fichier mappé en mémoire.

Il peut également être nécessaire d'utiliser plusieurs vues si la taille du fichier est supérieure à la taille de l'espace mémoire logique de l'application disponible pour le mappage de mémoire (2 Go sur un ordinateur 32 bits).

Il existe deux types de vues : la vue d'accès continu et la vue d'accès aléatoire. Utilisez les vues d'accès continu pour un accès séquentiel à un fichier ; cette vue est recommandée pour les fichiers non persistants et les communications entre processus. Les vues d'accès aléatoire sont préférées pour l'utilisation de fichiers persistants.

Les fichiers mappés en mémoire sont accessibles via le gestionnaire de mémoire du système d'exploitation pour que le fichier soit partitionné automatiquement en plusieurs pages et accessible autant que nécessaire. Vous n'avez pas à gérer la mémoire vous-même.

L'illustration suivante montre comment plusieurs processus peuvent avoir conjointement des vues multiples et superposées du même fichier mappé en mémoire.

Vues multiples et superposées d'un fichier mappé en mémoire

Affiche les vues dans un fichier mappé en mémoire.

Programmation avec les fichiers mappés en mémoire

Le tableau suivant indique comment utiliser les objets de fichiers mappés en mémoire et leurs membres.

Tâche

Méthodes ou propriétés à utiliser

Pour obtenir un objet MemoryMappedFile qui représente le fichier mappé en mémoire persistant d'un fichier présent sur le disque.

Méthode MemoryMappedFile.CreateFromFile.

Pour obtenir un objet MemoryMappedFile qui représente un fichier mappé en mémoire non persistant (non associé à un fichier sur le disque).

Méthode MemoryMappedFile.CreateNew.

- ou -

Méthode MemoryMappedFile.CreateOrOpen.

Pour obtenir un objet MemoryMappedFile d'un fichier mappé en mémoire existant (persistant ou non persistant).

Méthode MemoryMappedFile.OpenExisting.

Pour obtenir un objet UnmanagedMemoryStream pour une vue d'accès séquentiel du fichier mappé en mémoire.

Méthode MemoryMappedFile.CreateViewStream.

Pour obtenir un objet UnmanagedMemoryAccessor pour une vue d'accès aléatoire d'un fichier mappé en mémoire.

Méthode MemoryMappedFile.CreateViewAccessor.

Pour obtenir un objet SafeMemoryMappedViewHandle à utiliser avec du code non managé.

Propriété MemoryMappedFile.SafeMemoryMappedFileHandle.

- ou -

Propriété MemoryMappedViewAccessor.SafeMemoryMappedViewHandle.

- ou -

Propriété MemoryMappedViewStream.SafeMemoryMappedViewHandle.

Pour différer l'allocation de mémoire tant que la vue n'est pas créée (fichiers non persistants uniquement).

(Pour déterminer la taille de la mémoire de pagination du système actuel, utilisez la propriété Environment.SystemPageSize.)

Méthode CreateNew avec la valeur MemoryMappedFileOptions.DelayAllocatePages.

- ou -

Méthodes CreateOrOpen qui ont une énumération MemoryMappedFileOptions comme paramètre.

Sécurité

Vous pouvez appliquer des droits d'accès lorsque vous créez un fichier mappé en mémoire, à l'aide des méthodes suivantes qui prennent une énumération MemoryMappedFileAccess comme paramètre :

Vous pouvez spécifier des droits d'accès pour l'ouverture d'un fichier mappé en mémoire existant à l'aide des méthodes OpenExisting qui prennent un MemoryMappedFileRights comme paramètre.

De plus, vous pouvez inclure un objet MemoryMappedFileSecurity qui contient des règles d'accès prédéfinies.

Pour appliquer des règles d'accès nouvelles ou modifiées à un fichier mappé en mémoire, utilisez la méthode SetAccessControl. Pour récupérer les règles d'accès ou d'audit d'un fichier existant, utilisez la méthode GetAccessControl.

Exemples

Fichiers mappés en mémoire persistants

Les méthodes CreateFromFile créent un fichier mappé en mémoire à partir d'un fichier existant stocké sur le disque.

L'exemple suivant crée une vue mappée en mémoire d'une partie d'un fichier extrêmement volumineux et en manipule une partie.

Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices

Class Program

    Sub Main()

        Dim offset As Long = &H10000000 ' 256 megabytes
        Dim length As Long = &H20000000 ' 512 megabytes

        ' Create the memory-mapped file.
        Using mmf = _
            MemoryMappedFile.CreateFromFile("c:\ExtremelyLargeImage.data", _
                                                        FileMode.Open,"ImgA")
            ' Create a random access view, from the 256th megabyte (the offset)
            ' to the 768th megabyte (the offset plus length).
            Using accessor = mmf.CreateViewAccessor(offset, length)

                Dim colorSize As Integer = Marshal.SizeOf(GetType(MyColor))
                Dim color As MyColor
                Dim i As Long = 0

                ' Make changes to the view.
                Do While (i < length)
                    accessor.Read(i, color)
                    color.Brighten(10)
                    accessor.Write(i, color)
                Loop

            End Using
        End Using
    End Sub
End Class

Public Structure MyColor

    Public Red As Short
    Public Green As Short
    Public Blue As Short
    Public Alpha As Short

    ' Make the view brighter.
    Public Sub Brighten(ByVal value As Short)
        Red = CType(Math.Min(Short.MaxValue, _
            (CType(Red, Integer) + value)), Short)
        Green = CType(Math.Min(Short.MaxValue, _
            (CType(Green, Integer) + value)), Short)
        Blue = CType(Math.Min(Short.MaxValue, _
            (CType(Blue, Integer) + value)), Short)
        Alpha = CType(Math.Min(Short.MaxValue, _
            (CType(Alpha, Integer) + value)), Short)
    End Sub
End Structure
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;

class Program
{
    static void Main(string[] args)
    {
        long offset = 0x10000000; // 256 megabytes
        long length = 0x20000000; // 512 megabytes

        // Create the memory-mapped file.
        using (var mmf = 
            MemoryMappedFile.CreateFromFile(@"c:\ExtremelyLargeImage.data",
                                                        FileMode.Open,"ImgA"))
        {
        // Create a random access view, from the 256th megabyte (the offset)
        // to the 768th megabyte (the offset plus length).
        using (var accessor = mmf.CreateViewAccessor(offset, length))
            {

                int colorSize = Marshal.SizeOf(typeof(MyColor));
                MyColor color;

                // Make changes to the view.
                for (long i = 0; i < length; i += colorSize)
                {
                    accessor.Read(i, out color);
                    color.Brighten(10);
                    accessor.Write(i, ref color);
                }
            }
        }

    }

    public struct MyColor
    {
        public short Red;
        public short Green;
        public short Blue;
        public short Alpha;

        // Make the view brigher.
        public void Brighten(short value)
        {
            Red = (short)Math.Min(short.MaxValue, (int)Red + value);
            Green = (short)Math.Min(short.MaxValue, (int)Green + value);
            Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
            Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
        }
    }

}

L'exemple suivant ouvre le même fichier mappé en mémoire pour un autre processus.

Imports System
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices

Class Program
    Public Shared Sub Main(ByVal args As String())
        ' Assumes another process has created the memory-mapped file.
        Using mmf = MemoryMappedFile.OpenExisting("ImgA")
            Using accessor = mmf.CreateViewAccessor(4000000, 2000000)
                Dim colorSize As Integer = Marshal.SizeOf(GetType(MyColor))
                Dim color As MyColor

                ' Make changes to the view.
                Dim i As Long = 0
                While i < 1500000
                    accessor.Read(i, color)
                    color.Brighten(30)
                    accessor.Write(i, color)
                    i += colorSize
                End While
            End Using
        End Using
    End Sub
End Class

Public Structure MyColor
    Public Red As Short
    Public Green As Short
    Public Blue As Short
    Public Alpha As Short

    ' Make the view brigher.
    Public Sub Brighten(ByVal value As Short)
        Red = CShort(Math.Min(Short.MaxValue, CInt(Red) + value))
        Green = CShort(Math.Min(Short.MaxValue, CInt(Green) + value))
        Blue = CShort(Math.Min(Short.MaxValue, CInt(Blue) + value))
        Alpha = CShort(Math.Min(Short.MaxValue, CInt(Alpha) + value))
    End Sub
End Structure
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;


class Program
{
    static void Main(string[] args)
    {
        // Assumes another process has created the memory-mapped file.
        using (var mmf = MemoryMappedFile.OpenExisting("ImgA"))
        {
            using (var accessor = mmf.CreateViewAccessor(4000000, 2000000))
            {
                int colorSize = Marshal.SizeOf(typeof(MyColor));
                MyColor color;

                // Make changes to the view.
                for (long i = 0; i < 1500000; i += colorSize)
                {
                    accessor.Read(i, out color);
                    color.Brighten(20);
                    accessor.Write(i, ref color);
                }
            }
        }
    }
}

public struct MyColor
{
    public short Red;
    public short Green;
    public short Blue;
    public short Alpha;

    // Make the view brigher.
    public void Brighten(short value)
    {
        Red = (short)Math.Min(short.MaxValue, (int)Red + value);
        Green = (short)Math.Min(short.MaxValue, (int)Green + value);
        Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
        Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
    }
}

Fichiers mappés en mémoire non persistants

Les méthodes CreateNew et CreateOrOpen créent un fichier mappé en mémoire qui n'est pas mappé à un fichier existant sur le disque.

L'exemple suivant est composé de trois processus distincts (applications console) qui écrivent des valeurs booléennes dans un fichier mappé en mémoire. La séquence d'actions suivante se produit :

  1. Le Process A crée le fichier mappé en mémoire et écrit une valeur dedans.

  2. Le Process B ouvre le fichier mappé en mémoire et écrit une valeur dedans.

  3. Le Process C ouvre le fichier mappé en mémoire et écrit une valeur dedans.

  4. Le Process A lit et affiche les valeurs du fichier mappé en mémoire.

  5. Une fois le Process A terminé avec le fichier mappé en mémoire, le fichier est immédiatement libéré par le garbage collection.

Pour exécuter cet exemple, procédez comme suit :

  1. Compilez les applications et ouvrez trois fenêtres d'invite de commandes.

  2. Dans la première fenêtre d'invite de commandes, exécutez le Process A.

  3. Dans la deuxième fenêtre d'invite de commandes, exécutez le Process B.

  4. Retournez au Process A et appuyez sur ENTRÉE.

  5. Dans la troisième fenêtre d'invite de commandes, exécutez le Process C.

  6. Retournez au Process A et appuyez sur ENTRÉE.

La sortie du Process A est la suivante :

Start Process B and press ENTER to continue.
Start Process C and press ENTER to continue.
Process A says: True
Process B says: False
Process C says: True

Processus A

Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading
Module Module1

    ' Process A:
    Sub Main()
        Using mmf As MemoryMappedFile = MemoryMappedFile.CreateNew("testmap", 10000)
            Dim mutexCreated As Boolean
            Dim mTex As Mutex = New Mutex(True, "testmapmutex", mutexCreated)
            Using Stream As MemoryMappedViewStream = mmf.CreateViewStream()
                Dim writer As BinaryWriter = New BinaryWriter(Stream)
                writer.Write(1)
            End Using
            mTex.ReleaseMutex()
            Console.WriteLine("Start Process B and press ENTER to continue.")
            Console.ReadLine()

            Console.WriteLine("Start Process C and press ENTER to continue.")
            Console.ReadLine()

            mTex.WaitOne()
            Using Stream As MemoryMappedViewStream = mmf.CreateViewStream()
                Dim reader As BinaryReader = New BinaryReader(Stream)
                Console.WriteLine("Process A says: {0}", reader.ReadBoolean())
                Console.WriteLine("Process B says: {0}", reader.ReadBoolean())
                Console.WriteLine("Process C says: {0}", reader.ReadBoolean())
            End Using
            mTex.ReleaseMutex()

        End Using

    End Sub

End Module
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;

class Program
{
    // Process A:
    static void Main(string[] args)
    {
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
        {


            bool mutexCreated;
            Mutex mutex = new Mutex(true, "testmapmutex", out mutexCreated);
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(1);
            }
            mutex.ReleaseMutex();

            Console.WriteLine("Start Process B and press ENTER to continue.");
            Console.ReadLine();

            Console.WriteLine("Start Process C and press ENTER to continue.");
            Console.ReadLine();

            mutex.WaitOne();
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("Process A says: {0}", reader.ReadBoolean());
                Console.WriteLine("Process B says: {0}", reader.ReadBoolean());
                Console.WriteLine("Process C says: {0}", reader.ReadBoolean());
            }
            mutex.ReleaseMutex();
        }
    }
}

Processus B

Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading
Module Module1
    ' Process B:
    Sub Main()
        Try
            Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("testmap")
                Dim mTex As Mutex = Mutex.OpenExisting("testmapmutex")
                mTex.WaitOne()
                Using Stream As MemoryMappedViewStream = mmf.CreateViewStream(1, 0)
                    Dim writer As BinaryWriter = New BinaryWriter(Stream)
                    writer.Write(0)
                End Using
                mTex.ReleaseMutex()
            End Using
        Catch noFile As FileNotFoundException
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first." & vbCrLf & noFile.Message)
        End Try

    End Sub

End Module
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;

class Program
{
    // Process B:
    static void Main(string[] args)
    {
        try
        {
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
            {

                Mutex mutex = Mutex.OpenExisting("testmapmutex");
                mutex.WaitOne();

                using (MemoryMappedViewStream stream = mmf.CreateViewStream(1, 0))
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(0);
                }
                mutex.ReleaseMutex();
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first.");
        }
    }
}

Processus C

Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading
Module Module1
    ' Process C:
    Sub Main()
        Try
            Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("testmap")
                Dim mTex As Mutex = Mutex.OpenExisting("testmapmutex")
                mTex.WaitOne()
                Using Stream As MemoryMappedViewStream = mmf.CreateViewStream(2, 0)
                    Dim writer As BinaryWriter = New BinaryWriter(Stream)
                    writer.Write(1)
                End Using
                mTex.ReleaseMutex()
            End Using
        Catch noFile As FileNotFoundException
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first, then B." & vbCrLf & noFile.Message)
        End Try

    End Sub

End Module
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;

class Program
{
    // Process C:
    static void Main(string[] args)
    {
        try
        {
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
            {

                Mutex mutex = Mutex.OpenExisting("testmapmutex");
                mutex.WaitOne();

                using (MemoryMappedViewStream stream = mmf.CreateViewStream(2, 0))
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(1);
                }
                mutex.ReleaseMutex();
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first, then B.");
        }
    }
}

Voir aussi

Autres ressources

Fichier et flux de données E/S