Para ver el artículo en inglés, active la casilla Inglés. También puede ver el texto en inglés en una ventana emergente si pasa el puntero del mouse por el texto.
Traducción
Inglés

Archivos asignados a memoria

.NET Framework (current version)
 

Un archivo asignado a memoria incluye el contenido de un archivo en la memoria virtual. Esta asignación entre un archivo y el espacio de memoria permite a una aplicación, incluidos varios procesos, modificar el archivo leyendo y escribiendo directamente en la memoria. A partir de .NET Framework 4, se puede usar código administrado para tener acceso a los archivos asignados a memoria del mismo modo que las funciones de Windows nativas tienen acceso a los archivos asignados a memoria, tal como se describe en Administración de archivos asignados a memoria en Win32 en MSDN Library.

Hay dos tipos de archivos asignados a memoria:

  • Archivos asignados a memoria persistentes

    Los archivos persistentes son archivos asignados a memoria que están asociados a un archivo de origen ubicado en un disco. Cuando el último proceso termina de usar el archivo, los datos se guardan en el archivo de origen ubicado en el disco. Estos archivos asignados a memoria son idóneos para trabajar con archivos de origen muy grandes.

  • Archivos asignados a memoria no persistentes

    Los archivos no persistentes son archivos asignados a memoria que no están asociados a un archivo ubicado 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 idóneos para crear memoria compartida para las comunicaciones entre procesos (IPC).

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

Para trabajar con un archivo asignado a memoria, debe crear una vista de todo o parte del archivo asignado a memoria. También puede crear varias vistas a la misma parte del archivo asignado a memoria, creando de esta forma memoria simultánea. Para que dos vistas sigan siendo simultáneas, tienen que crearse a partir del mismo archivo asignado a memoria.

También puede ser necesario el uso de 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. Use las vistas de acceso secuencial para obtener acceso secuencial a un archivo; es la vista recomendada para los archivos no persistentes y las IPC. Se recomiendan usar las vistas de acceso aleatorio para trabajar con archivos persistentes.

El acceso a los archivos asignados a memoria se realiza a través del administrador de memoria del sistema operativo, de modo que el archivo se divide automáticamente en varias páginas y el acceso se realizará según sea necesario. El usuario no tiene que encargarse de administrar la memoria.

En la siguiente ilustración se muestra cómo varios procesos pueden presentar simultáneamente varias vistas superpuestas del mismo archivo asignado a memoria.

Muestra vistas en un archivo asignado a la memoria.

Varias visas superpuestas de un archivo asignado a memoria

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 usan

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 objeto MemoryMappedFile que representa un archivo asignado a memoria no persistente (no asociado a ningún archivo en disco).

Método MemoryMappedFile.CreateNew.

– O bien –

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 de una vista de acceso secuencial al archivo asignado a 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 bien –

Propiedad MemoryMappedViewAccessor.SafeMemoryMappedViewHandle.

– O bien –

Propiedad MemoryMappedViewStream.SafeMemoryMappedViewHandle.

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

(Para determinar el actual tamaño de página del sistema, utilice la propiedad Environment.SystemPageSize.)

Método CreateNew con el valor MemoryMappedFileOptions.DelayAllocatePages.

– O bien –

Métodos CreateOrOpen con la enumeración MemoryMappedFileOptions como parámetro.

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:

Se pueden especificar derechos de acceso para abrir un archivo asignado a memoria existente si se usan los métodos OpenExisting con la enumeración MemoryMappedFileRights como parámetro.

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

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

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

En el ejemplo siguiente se crea una vista asignada a memoria de una parte de un archivo muy grande y se manipula una parte de él.

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

En el siguiente ejemplo, 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);
    }
}

Los métodos CreateOrOpen y CreateNew crean un archivo asignado a memoria que no está asignado 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 asignado a memoria 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 asignado a 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

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

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

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