C# 中的内存共享(Shared Memory)
在.net中是通过操作系统系统的内存管理器来进行操作的,管理器会自动将共享内存文件分页,并根据需要对其进行访问。不需要手动去处理内存管理。
内存映射文件允许你保留一块地址空间,然后将物理存储映射到这块内存空间中进行操作。物理存储有文件系统管理;内存映射文件是操作系统级内存管理。
内存映射文件分为两种类型:
持久内存映射文件 | 持久内存映射文件是与磁盘上的源文件关联的内存映射文件。在最后一个进程使用完此文件后,数据将保存到磁盘上的源文件中。这些内存映射文件适合用来处理非常大的源文件。 |
非持久内春映射文件 | 非持久内存映射文件是未与磁盘上的源文件关联的内存映射文件。当最后一个进程使用完此文件后,数据将丢失,并且垃圾回收功能将回收此文件。这些文件实用于为进程间通信(IPC)创建共享内存。 |
可以跨拖个进程共享内存映射文件。进程可以映射到相同的内存一映射文件,只需要使用文件创建进程分配通用名称即可。
必须内存映射文件的视图,才能使用内春映射文件。可以为内存映射文件的同意部分创建多个视图,从而创建并发内存。若要使两个视图一直处于并发状态,必须通过容易个内存映射文件创建他们。如果文件大于内存映射的逻辑内存空间(在 32 位计算机上为2GB),则还需要使用多个视图。
视图可以分为两种类型:流访问视图和随机访问视图。
流访问视图:可以对文件进行顺序访问;
随机访问视图:在使用持久文件的首选方法;
多进程如何同时使用一个内存映射文件,以及重叠视图
由于内存映射文件是通过操作系统的内存管理程序进行访问,因此文件会被自动分区到很多页面,并根据需要进行访问。 无需自行处理内存管理。
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();
}
}
}
命名空间:System.IO.MemoryMappedFiles.dll
程序集:System.IO.MemoryMappedFiles
该类提供了内存映射文件的创建,视图的创建等方法实现。
属性 | |
---|---|
SafeMemoryMappedFileHandle | 获取内存映射文件的文件句柄。 |
方法 | |
---|---|
CreateFromFile(FileStream, String, Int64, MemoryMappedFileAccess, HandleInheritability, Boolean) | 从现有文件创建一个具有指定的访问模式、名称、继承性和容量的内存映射文件。 |
CreateFromFile(String) | 基于磁盘上的文件创建一个内存映射文件。 |
CreateFromFile(String, FileMode, String) | 基于磁盘上的文件创建一个具有指定访问模式和名称的内存映射文件。 |
CreateFromFile(String, FileMode, String, Int64) | 基于磁盘上的文件创建一个具有指定访问模式、名称和容量的内存映射文件。 |
CreateFromFile(String, FileMode, String, Int64, MemoryMappedFileAccess) | 基于磁盘上的文件创建一个具有指定访问模式、名称、容量和访问类型的内存映射文件。 |
CreateNew(String, Int64) | 在系统内存中创建一个具有指定容量的内存映射文件。 |
CreateNew(String, Int64, MemoryMappedFileAccess) | 在系统内存中创建一个具有指定容量和访问类型的内存映射文件。 |
CreateNew(String, Int64, MemoryMappedFileAccess, MemoryMappedFileOptions, HandleInheritability) | 创建一个具有指定名称、容量、访问类型、内存分配选项和继承性的内存映射文件。 |
CreateOrOpen(String, Int64) | 在系统内存中创建或打开具有指定名称和容量的内存映射文件。 |
CreateOrOpen(String, Int64, MemoryMappedFileAccess) | 在系统内存中创建或打开具有指定名称、容量和访问类型的内存映射文件。 |
CreateOrOpen(String, Int64, MemoryMappedFileAccess, MemoryMappedFileOptions, HandleInheritability) | 创建一个新的空内存映射文件或打开一个现有的内存映射文件(如果存在同名的内存映射文件)。 如果打开现有的文件,则会忽略容量、选项和内存参数。 |
CreateViewAccessor() | 创建映射到内存映射文件视图的 MemoryMappedViewAccessor。 |
CreateViewAccessor(Int64, Int64) | 创建一个 MemoryMappedViewAccessor,它映射到内存映射文件的视图并具有指定的偏移和大小。 |
CreateViewStream() | 创建映射到内存映射文件视图的流。 |
CreateViewStream(Int64, Int64) | 创建一个流,它映射到内存映射文件的视图并具有指定的偏移和大小。 |
CreateViewStream(Int64, Int64, MemoryMappedFileAccess) | 创建一个流,它映射到内存映射文件的视图,并具有指定的偏移、大小和访问类型。 |
Dispose() | 释放由 MemoryMappedFile 使用的所有资源。 |
Dispose(Boolean) | 释放由 MemoryMappedFile 占用的非托管资源,还可以另外再释放托管资源。 |
Equals(Object) | 确定指定对象是否等于当前对象。 |
(继承自 Object) GetHashCode() | 作为默认哈希函数。 |
(继承自 Object)GetType() | 获取当前实例的 Type。 |
(继承自 Object) MemberwiseClone() | 创建当前 Object 的浅表副本。 |
(继承自 Object)OpenExisting(String) | 在系统内存中打开一个具有指定名称的现有内存映射文件。 |
OpenExisting(String, MemoryMappedFileRights) | 在系统内存中打开一个具有指定名称和访问权限的现有内存映射文件。 |
OpenExisting(String, MemoryMappedFileRights, HandleInheritability) | 在系统内存中打开一个具有指定名称、访问权限和继承性的现有内存映射文件。 |
ToString()(继承自 Object) | 返回表示当前对象的字符串。 |
命名空间:System.Runtime.InteropServices
程序集:System.Runtime.InteropServices.dll
用于分配非托管内存,复制非托管内存块和将托管类型转换为非托管类型的方法集合,以及其他用于与非托管代码交互时使用的杂项方法。
public static class Marshal
查阅MicrosoftAPI
命名空间:System.Runtime.InteropServices
程序集:System.Runtime.dll
public struct GCHandle : IEquatable
提供从非托管内存访问托管对象的方法
属性 | |
---|---|
IsAllocated | 获取一个值,该值指示是否分配了句柄。 |
Target | 获取或设置该句柄表示的对象。 |
方法 | |
---|---|
AddrOfPinnedObject() | 在 Pinned 句柄中检索对象数据的地址。 |
Alloc(Object) | 为指定的对象分配 Normal 句柄。 |
Alloc(Object, GCHandleType) | 为指定的对象分配指定类型的句柄。 |
Equals(GCHandle) | 指示当前实例是否等于同一类型的另一个实例。 |
Equals(Object) | 确定指定的 GCHandle 对象是否等同于当前的 GCHandle。 |
Free() | 释放 GCHandle。 |
FromIntPtr(IntPtr) | 返回从某个托管对象的句柄创建的新 GCHandle 对象。 |
GetHashCode() | 返回当前 GCHandle 对象的标识符。 |
ToIntPtr(GCHandle) | 返回 GCHandle 对象的内部整数表示形式。 |
运算符 | |
---|---|
Equality(GCHandle, GCHandle) | 返回一个值,该值指示两个 GCHandle 对象是否相等。 |
Explicit(GCHandle to IntPtr) | GCHandle 以内部整数表示形式存储。 |
Explicit(IntPtr to GCHandle) | GCHandle 以内部整数表示形式存储。 |
Inequality(GCHandle, GCHandle) | 返回一个值,该值指示两个 GCHandle 对象是否不相等。 |
dll:Kernel.dll
C#引用 :
//创建内存映射文件
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CreateFileMapping(int hFile, IntPtr ipAtttribute, uint flProtect, uint dwMaxSize, uint dwMaxSizeLow, string ipName);
//打开内存映射文件
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr OpenFileMapping(int dwDesAccess, [MarshalAs(UnmanagedType.Bool)] bool blHeritHanndle, string IpName);
//创建视图
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesireAccess, uint dwFileOffSetHigh, uint dwFileOffSetLow, uint dwNumberOfbytesToMap);
//关闭视图
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);
//释放句柄
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr hanndle);
C++
HANDLE OpenFileMappingW(
[in] DWORD dwDesiredAccess,
[in] BOOL bInheritHandle,
[in] LPCWSTR lpName
);
HANDLE CreateFileMappingW(
[in] HANDLE hFile,
[in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
[in] DWORD flProtect,
[in] DWORD dwMaximumSizeHigh,
[in] DWORD dwMaximumSizeLow,
[in, optional] LPCWSTR lpName
);
LPVOID MapViewOfFile(
[in] HANDLE hFileMappingObject,
[in] DWORD dwDesiredAccess,
[in] DWORD dwFileOffsetHigh,
[in] DWORD dwFileOffsetLow,
[in] SIZE_T dwNumberOfBytesToMap
);
BOOL UnmapViewOfFile(
[in] LPCVOID lpBaseAddress
);
BOOL CloseHandle(
[in] HANDLE hObject
);