Compartir a través de


Archivos asignados a memoria

Un archivo mapeado en memoria almacena el contenido de un archivo en memoria virtual. Esta asignación entre un archivo y un espacio de memoria permite a una aplicación, incluidos varios procesos, modificar el archivo leyendo y escribiendo directamente en la memoria. Puede usar código administrado para acceder a los archivos asignados a memoria de la misma manera que las funciones nativas de Windows acceden a archivos asignados a memoria, como se describe en Administración de archivos Memory-Mapped.

Hay dos tipos de archivos mapeados en memoria.

  • Archivos asignados a memoria persistentes

    Los archivos persistentes son archivos asignados a memoria asociados a un archivo de origen en un disco. Cuando el último proceso ha terminado de trabajar con el archivo, los datos se guardan en el archivo de origen en el disco. Estos archivos mapeados en memoria son adecuados para trabajar con archivos extremadamente grandes.

  • Archivos asignados a memoria no persistentes

    Los archivos no persistentes son archivos asignados a memoria que no están asociados a un archivo en un disco. Cuando el último proceso termina de usar el archivo, se pierden los datos y la recolección de elementos no utilizados reclama el archivo. Estos archivos son adecuados para crear memoria compartida para las comunicaciones entre procesos (IPC).

Procesos, vistas y administración de memoria

Los archivos asignados a memoria se pueden compartir entre varios procesos. Los procesos pueden asignarse al mismo archivo asignado a memoria mediante un nombre común asignado por el proceso que creó el archivo.

Para trabajar con un archivo mapeado en memoria, debe crear una vista de todo el archivo mapeado en memoria o de una parte de él. También puede crear varias vistas en la misma parte del archivo asignado a memoria, lo que crea memoria simultánea. Para que dos vistas permanezcan simultáneas, deben crearse a partir del mismo archivo asignado a memoria.

También puede ser necesario tener varias vistas si el archivo es mayor que el tamaño del espacio de memoria lógico de la aplicación disponible para la asignación de memoria (2 GB en un equipo de 32 bits).

Hay dos tipos de vista: vista de acceso secuencial y vista de acceso aleatorio. Usar vistas de acceso de flujo para el acceso secuencial a un archivo. Esto se recomienda para archivos no persistentes y comunicación entre procesos (IPC). Se prefieren vistas de acceso aleatorio para trabajar con archivos persistentes.

Se accede a los archivos asignados a memoria a través del administrador de memoria del sistema operativo, por lo que el archivo se divide automáticamente en una serie de páginas y se accede a ellos según sea necesario. No tiene que controlar la administración de memoria usted mismo.

En la ilustración siguiente se muestra cómo varios procesos pueden tener vistas múltiples y superpuestas al mismo archivo asignado a memoria al mismo tiempo.

En la imagen siguiente se muestran varias vistas superpuestas de un archivo asignado a memoria:

Captura de pantalla que muestra vistas de un archivo asignado a la memoria.

Programación con archivos Memory-Mapped

En la siguiente tabla, se describe cómo usar los objetos de archivo asignado a memoria y sus miembros.

Tarea Métodos o propiedades que se van a usar
Para obtener un objeto MemoryMappedFile que representa un archivo asignado a memoria persistente de un archivo en disco. Método MemoryMappedFile.CreateFromFile.
Para obtener un MemoryMappedFile objeto que representa un archivo asignado a memoria no persistente (no asociado a un archivo en disco). Método MemoryMappedFile.CreateNew.

- o -

Método MemoryMappedFile.CreateOrOpen.
Para obtener un objeto MemoryMappedFile de un archivo asignado a memoria existente (persistente o no persistente). Método MemoryMappedFile.OpenExisting.
Para obtener un objeto UnmanagedMemoryStream para una vista de acceso secuencial al archivo mapeado en memoria. Método MemoryMappedFile.CreateViewStream.
Para obtener un objeto UnmanagedMemoryAccessor de una vista de acceso aleatorio a un archivo asignado a memoria. Método MemoryMappedFile.CreateViewAccessor.
Para obtener un objeto SafeMemoryMappedViewHandle que se va a usar con código no administrado. Propiedad MemoryMappedFile.SafeMemoryMappedFileHandle.

- o -

Propiedad MemoryMappedViewAccessor.SafeMemoryMappedViewHandle.

- o -

Propiedad MemoryMappedViewStream.SafeMemoryMappedViewHandle.
Para retrasar la asignación de memoria hasta que se crea una vista (solo archivos no persistentes).

(Para determinar el tamaño de página del sistema actual, use la Environment.SystemPageSize propiedad ).
Método CreateNew con el valor MemoryMappedFileOptions.DelayAllocatePages.

- o -

CreateOrOpen métodos que tienen una MemoryMappedFileOptions enumeración como parámetro.

Seguridad

Se pueden aplicar derechos de acceso cuando se crea un archivo asignado a memoria si se usan los siguientes métodos con la enumeración MemoryMappedFileAccess como parámetro:

Puede especificar los derechos de acceso para abrir un archivo existente asignado a memoria utilizando los métodos OpenExisting que toman un MemoryMappedFileRights como parámetro.

Además, puede incluir un MemoryMappedFileSecurity objeto que contenga reglas de acceso predefinidas.

Para aplicar reglas de acceso nuevas o modificadas a un archivo asignado a memoria, use el SetAccessControl método . Para recuperar reglas de acceso o auditoría de un archivo existente, use el GetAccessControl método .

Ejemplos

Archivos asignados a memoria persistentes

Los CreateFromFile métodos crean un archivo asignado a memoria a partir de un archivo existente en el disco.

En el ejemplo siguiente se crea una vista asignada a memoria de una parte de un archivo extremadamente grande y se manipula una sección del mismo.

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

En el ejemplo siguiente se abre el mismo archivo asignado a memoria para otro proceso.

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

Archivos asignados a memoria no persistentes

CreateNew y CreateOrOpen métodos crean un archivo mapeado en memoria que no está mapeado a un archivo existente en el disco.

El ejemplo siguiente consta de tres procesos independientes (aplicaciones de consola) que escriben valores booleanos en un archivo asignado a memoria. Se produce la siguiente secuencia de acciones:

  1. Process A crea el archivo de memoria mapeada y escribe un valor en él.

  2. Process B abre el archivo asignado a memoria y escribe un valor en él.

  3. Process C abre el archivo asignado a memoria y escribe un valor en él.

  4. Process A lee y muestra los valores del archivo mapeado en memoria.

  5. Una vez que Process A termina con el archivo asignado a memoria, la recolección de elementos no utilizados recupera el archivo inmediatamente.

Para ejecutar este ejemplo, haga lo siguiente:

  1. Compile las aplicaciones y abra tres ventanas de símbolo del sistema.

  2. En la primera ventana de símbolo del sistema, ejecute Process A.

  3. En la segunda ventana de símbolo del sistema, ejecute Process B.

  4. Vuelva a Process A y presione ENTRAR.

  5. En la tercera ventana de símbolo del sistema, ejecute Process C.

  6. Vuelva a Process A y presione ENTRAR.

La salida de Process A es la siguiente:

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  

Procesar 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

Proceso 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

Procesar 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

Consulte también