Partager via


Fichiers mappés en mémoire

Un fichier mappé en mémoire contient le contenu d’un fichier en mémoire virtuelle. Ce mappage entre un fichier et un espace mémoire permet à une application, y compris plusieurs processus, de modifier le fichier en lisant et en écrivant directement dans la mémoire. Vous pouvez 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 Memory-Mapped.

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

  • Fichiers mappés en mémoire persistante

    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 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 le ramasse-miettes. Ces fichiers sont adaptés à la création d’une mémoire partagée pour les communications interprocesseur (IPC).

Processus, vues et gestion de la mémoire

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

Pour utiliser un fichier mappé en mémoire, vous devez créer une vue de l’ensemble du fichier mappé en mémoire ou d’une partie de celui-ci. Vous pouvez également créer plusieurs vues dans la même partie du fichier mappé en mémoire, créant ainsi une mémoire simultanée. Pour que deux vues restent simultanées, elles doivent être créées à partir du même fichier mappé en mémoire.

Plusieurs vues peuvent également être nécessaires si le fichier est supérieur à 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 en flux et la vue d’accès aléatoire. Utilisez des vues d’accès en flux pour l’accès séquentiel à un fichier ; ceci est recommandé pour les fichiers non persistants et IPC. Les vues d’accès aléatoire sont préférées pour utiliser des fichiers persistants.

Les fichiers mappés en mémoire sont accessibles via le gestionnaire de mémoire du système d’exploitation. Le fichier est donc automatiquement partitionné en plusieurs pages et accessible en fonction des besoins. Vous n’avez pas besoin de gérer vous-même la gestion de la mémoire.

L’illustration suivante montre comment plusieurs processus peuvent avoir plusieurs vues qui se chevauchent dans le même fichier mappé en mémoire en même temps.

L’image suivante montre plusieurs vues qui se chevauchent dans un fichier mappé en mémoire :

Capture d’écran montrant les vues dans un fichier mappé en mémoire.

Programmation avec des fichiers Memory-Mapped

Le tableau suivant fournit un guide pour l’utilisation d’objets de fichier mappés en mémoire et de leurs membres.

Tâche Méthodes ou propriétés à utiliser
Pour obtenir un MemoryMappedFile objet qui représente un fichier mappé en mémoire persistante à partir d’un fichier sur disque. MéthodeMemoryMappedFile.CreateFromFile .
Pour obtenir un MemoryMappedFile objet qui représente un fichier mappé en mémoire non persistant (non associé à un fichier sur le disque). MéthodeMemoryMappedFile.CreateNew .

ou

MéthodeMemoryMappedFile.CreateOrOpen .
Pour obtenir un objet MemoryMappedFile d’un fichier mappé en mémoire existant (persistant ou non persistant). MéthodeMemoryMappedFile.OpenExisting .
Pour obtenir un objet UnmanagedMemoryStream pour une vue à accès séquentiel dans le fichier mappé en mémoire. MéthodeMemoryMappedFile.CreateViewStream .
Pour obtenir un UnmanagedMemoryAccessor objet pour une vue d’accès aléatoire à un fichier mappé en mémoire. MéthodeMemoryMappedFile.CreateViewAccessor .
Pour obtenir un SafeMemoryMappedViewHandle objet à utiliser avec du code non managé. Propriété MemoryMappedFile.SafeMemoryMappedFileHandle.

ou

Propriété MemoryMappedViewAccessor.SafeMemoryMappedViewHandle.

ou

Propriété MemoryMappedViewStream.SafeMemoryMappedViewHandle.
Pour retarder l’allocation de mémoire jusqu’à ce qu’une vue soit créée (fichiers non persistants uniquement).

(Pour déterminer la taille actuelle de la page système, utilisez la Environment.SystemPageSize propriété.)
Méthode CreateNew avec la valeur MemoryMappedFileOptions.DelayAllocatePages.

ou

CreateOrOpen méthodes qui ont une MemoryMappedFileOptions énumération 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 MemoryMappedFileAccess énumération en tant que paramètre :

Vous pouvez spécifier des droits d’accès pour ouvrir un fichier mappé en mémoire existant en utilisant les méthodes OpenExisting qui acceptent un paramètre MemoryMappedFileRights.

En outre, vous pouvez inclure un objet qui contient des règles d’accès MemoryMappedFileSecurity prédéfinies.

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

Exemples

Fichiers mappés en mémoire persistants

Les CreateFromFile méthodes créent un fichier mappé en mémoire à partir d’un fichier existant 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 manipule une partie de celui-ci.

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 brighter.
    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);
    }
}
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)
                    i += colorSize
                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

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

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);
    }
}
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

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 associé à un fichier existant sur le disque.

L’exemple suivant se compose 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. Process A crée le fichier mappé en mémoire et écrit une valeur dans celui-ci.

  2. Process B ouvre le fichier mappé en mémoire et écrit une valeur dans celui-ci.

  3. Process C ouvre le fichier mappé en mémoire et écrit une valeur dans celui-ci.

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

  5. Une fois que Process A a terminé avec le fichier mappé en mémoire, celui-ci est immédiatement récupéré par la collecte des ordures.

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

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

  2. Dans la première fenêtre d’invite de commande, exécutez Process A.

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

  4. Revenez à Process A et appuyez sur Entrée.

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

  6. Revenez à Process A et appuyez sur Entrée.

La sortie de 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

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: {reader.ReadBoolean()}");
                Console.WriteLine($"Process B says: {reader.ReadBoolean()}");
                Console.WriteLine($"Process C says: {reader.ReadBoolean()}");
            }
            mutex.ReleaseMutex();
        }
    }
}
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

Processus B

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.");
        }
    }
}
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

Processus C

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.");
        }
    }
}
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

Voir aussi