【微软技术栈】C#.NET 内存映射文件

news2024/11/28 20:41:05

本文内容

  1. 进程、视图和管理内存
  2. 使用内存映射文件编程
  3. 示例

内存映射文件包含虚拟内存中文件的内容。 借助文件和内存空间之间的这种映射,应用(包括多个进程)可以直接对内存执行读取和写入操作,从而修改文件。 可以使用托管代码访问内存映射文件,就像本机 Windows 函数访问内存映射文件(如管理内存映射文件中所述)一样。

内存映射文件分为两种类型:

  • 持久化内存映射文件

    持久化文件是与磁盘上的源文件相关联的内存映射文件。 当最后一个进程处理完文件时,数据保存到磁盘上的源文件中。 此类内存映射文件适用于处理非常大的源文件。

  • 非持久化内存映射文件

    非持久化文件是不与磁盘上的文件相关联的内存映射文件。 当最后一个进程处理完文件时,数据会丢失,且文件被垃圾回收器回收。 此类文件适合创建共享内存,以进行进程内通信 (IPC)。

1、进程、视图和管理内存

可以跨多个进程共享内存映射文件。 进程可以映射到相同的内存映射文件,只需使用文件创建进程分配的通用名称即可。

必须创建整个或部分内存映射文件的视图,才能使用内存映射文件。 还可以为内存映射文件的同一部分创建多个视图,从而创建并发内存。 若要让两个视图一直处于并发状态,必须通过同一个内存映射文件创建它们。

如果文件大于可用于内存映射的应用程序逻辑内存空间(在 32 位计算机中为 2 GB),可能也有必要使用多个视图。

视图分为以下两种类型:流访问视图和随机访问视图。 使用流访问视图,可以顺序访问文件;建议对非持久化文件和 IPC 使用这种类型。 随机访问视图是处理持久化文件的首选类型。

由于内存映射文件是通过操作系统的内存管理程序进行访问,因此文件会被自动分区到很多页面,并根据需要进行访问。 无需自行处理内存管理。

下图展示了多个进程如何同时对同一个内存映射文件有多个重叠视图。

下图显示了内存映射文件的多个重叠视图:

显示内存映射文件的视图的屏幕截图。

2、使用内存映射文件编程

下表列出了与使用内存映射文件对象及其成员相关的指南。

任务要使用的方法或属性
从磁盘上的文件获取表示持久化内存映射文件的 MemoryMappedFile 对象。MemoryMappedFile.CreateFromFile 方法。
获取表示非持久化内存映射文件的 MemoryMappedFile 对象(未与磁盘上的文件关联)。MemoryMappedFile.CreateNew 方法。

- 或 -

MemoryMappedFile.CreateOrOpen 方法。
获取现有内存映射文件(持久化或非持久化)的 MemoryMappedFile 对象。MemoryMappedFile.OpenExisting 方法。
获取内存映射文件的顺序访问视图的 UnmanagedMemoryStream 对象。MemoryMappedFile.CreateViewStream 方法。
获取内存映射文件的随机访问视图的 UnmanagedMemoryAccessor 对象。MemoryMappedFile.CreateViewAccessor 方法。
获取要与非托管代码结合使用的 SafeMemoryMappedViewHandle 对象。MemoryMappedFile.SafeMemoryMappedFileHandle 属性。

- 或 -

MemoryMappedViewAccessor.SafeMemoryMappedViewHandle 属性。

- 或 -

MemoryMappedViewStream.SafeMemoryMappedViewHandle 属性。
将内存分配一直延迟到视图创建完成(仅限非持久化文件)。

(若要确定当前系统页面大小,请使用 Environment.SystemPageSize 属性。)
值为 MemoryMappedFileOptions.DelayAllocatePages 的 CreateNew 方法。

- 或 -

将 MemoryMappedFileOptions 枚举用作参数的 CreateOrOpen 方法。

2.1 安全性

可以在创建内存映射文件时应用访问权限,具体操作是运行以下需要将 MemoryMappedFileAccess 枚举用作参数的方法:

  • MemoryMappedFile.CreateFromFile

  • MemoryMappedFile.CreateNew

  • MemoryMappedFile.CreateOrOpen

若要指定打开现有内存映射文件所需的访问权限,可以运行需要将 MemoryMappedFileRights 用作参数的 OpenExisting 方法。

另外,还可以添加包含预定义访问规则的 MemoryMappedFileSecurity 对象。

若要将新的或更改后的访问规则应用于内存映射文件,请使用 SetAccessControl 方法。 若要从现有文件检索访问或审核规则,请使用 GetAccessControl 方法。

3、示例

3.1 持久化内存映射文件

CreateFromFile 方法通过磁盘上的现有文件创建内存映射文件。

下面的示例为极大文件的一部分创建内存映射视图,并控制其中一部分。

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

下面的示例为另一个进程打开相同的内存映射文件。

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

3.2 非持久化内存映射文件

CreateNew 和 CreateOrOpen 方法创建未映射到磁盘上现有文件的内存映射文件。

下面的示例包含三个独立进程(控制台应用),以将布尔值写入内存映射文件。 各操作按下面的顺序发生:

  1. Process A 创建内存映射文件,并向其中写入值。

  2. Process B 打开内存映射文件,并向其中写入值。

  3. Process C 打开内存映射文件,并向其中写入值。

  4. Process A 读取并显示内存映射文件中的值。

  5. 在 Process A 处理完内存映射文件后,此文件立即被垃圾回收器回收。

若要运行此示例,请按照以下步骤操作:

  1. 编译应用并打开三个命令提示符窗口。

  2. 在第一个命令提示符窗口中,运行 Process A

  3. 在第二个命令提示符窗口中,运行 Process B

  4. 返回到 Process A,再按 Enter。

  5. 在第三个命令提示符窗口中,运行 Process C

  6. 返回到 Process A,再按 Enter。

Process A 的输出如下所示:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1218476.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Spring Boot中使用Redis的发布订阅功能

Redis的发布订阅模式是一种消息传递模式&#xff0c;它允许多个订阅者订阅一个或多个频道&#xff0c;同时一个发布者可以将消息发布到指定的频道。这种模式在分布式系统中非常有用&#xff0c;可以解决以下问题&#xff1a; 实时消息传递&#xff1a;发布订阅模式可以用于实时…

【洛谷算法题】P5712-Apples【入门2分支结构】

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5712-Apples【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格式&…

linux运行java程序

这个帖子实现的是linux上运行java代码 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 事情发生的原因是博洋需要知道海外城市的数量&#xff0c;我一开始准备将全量数据拉取到本地&#xff0c;用代码遍历一遍。但是打包好全量数据&…

数据结构 链表

单链表&#xff1a;单链表用来写邻接表&#xff0c;邻接表用来存储图和树 双链表&#xff1a;用来优化某些问题 单链表 链式存储 #include<stdio.h> #include<stdlib.h> int cont 0; //结构体 typedef struct List { int data; //数据域 struct List* next; //…

实战:给docusaurus文档网站配置Algolia 实现全站内容搜索功能-2023.11.16(已解决)

更新于&#xff1a;2023年11月16日 次文档已全部脱敏&#xff01; 实战&#xff1a;给docusaurus文档网站配置Algolia 实现全站内容搜索功能-2023.11.16(已解决) 目录 前提条件 &#x1f340; 前提条件 具备docker环境 具有自己的网站 &#x1f340; 实验软件&#xff08…

【BIM入门实战】Revit属性对话框中“视图范围”工具的使用方法详解

每个平面图都具有视图范围属性&#xff0c;也称为可见范围。视图范围是一组水平平面&#xff0c;可以控制视图中对象的可见性和外观。水平面为顶部平面、剖切面和底部平面。顶部切割平面和底部切割平面表示视图范围的顶部和底部。剖切面是确定视图中某些图元可视剖切面高度的平…

Android JNI静态和动态注入方法

作者&#xff1a;MiniCode Android调用C/C的代码目前比较流行的方式之一便是通过JNI&#xff0c;其中按本地方法的实现有两种方式&#xff1a;静态和动态 创建一个C项目或者C的Module&#xff1a; 创建成功之后会生成如下文件&#xff08;CMakeLists.txt、nativelib.cpp&#…

C#,数值计算——插值和外推,Base_interp的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Abstract base class used by all interpolation routines in this chapter. /// Only the routine interp is called directly by the user. /// </summary> pu…

SoftwareTest8 - 怎样测试一个系统的性能 ?

Hello , 大家好 , 又给大家带来新的专栏喽 ~ 这个专栏是专门为零基础小白从 0 到 1 了解软件测试基础理论设计的 , 虽然还不足以让你成为软件测试行业的佼佼者 , 但是可以让你了解一下软件测试行业的相关知识 , 具有一定的竞争实力 . 这篇文章是带着大家先了解一些性能测试的概…

回调方法Callbak方法的理解——Java中回调的实现方式 从系统调用角度理解回调

目录 回调方法实现用反射实现直接调用callback进化&#xff1a;接口实现分离 匿名内部类 到 函数式编程 从系统调用角度理解回调同步调用异步调用不需要对方结果需要对方的结果 菜鸡问大佬问题案例同步回调异步回调基于Future的半同步 回调方法就是一个参数,将一个A方法作为参数…

filter - 常用滤镜效果(毛玻璃、图片阴影、图片褪色)

文章目录 filter 属性滤镜算法函数blur&#xff1a;高斯模糊hue-rotate&#xff1a;色相环contrast&#xff1a;对比度grayscale&#xff1a;灰度drop-shadow&#xff1a;图片阴影 常见的滤镜效果图片内容轮廓阴影毛玻璃图片黑白调整图片色相和对比度使元素或文字变圆润 filter…

linux实现SSH免密登录设置,以及shell脚本实现

原创/朱季谦 最近在搭建linux集群&#xff0c;做了SSH免密登录的设置&#xff0c;正好把过程记录一下&#xff1a; 一.用搭建好的两台虚拟机做演示&#xff0c;A机器&#xff1a;192.168.200.129&#xff0c;B机器&#xff1a;192.168.200.128 二.分别在两台机器上执行以下步…

Excel Unix时间戳和日期时间格式的相互转换

时间戳转日期时间 ((A18*3600)/86400)DATE(1970,1,1) # 或 (A18*3600)/8640070*36519# 带格式化 TEXT((C18*3600)/8640070*36519,"yyyy-mm-dd hh:mm:ss")首先加8小时进行时区转换&#xff0c;然后转换成天数&#xff0c;再加上1970年1月1日&#xff0c;最后设置日期…

类和对象(7):初始化列表

class Date { public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}private:int _year;int _month;int _day; };构造函数体内的语句只能称为赋初值&#xff0c;不能称为初始化。初始化只能初始化一次&#xff0c;而构造函数体内可以多次…

面向企业的人脸属性检测技术方案

人脸识别技术已经成为企业提升服务质量、优化用户体验的重要工具。美摄科技&#xff0c;作为领先的人工智能技术提供商&#xff0c;我们致力于为企业提供最先进、最全面的人脸属性检测技术解决方案。 我们的AI人脸检测与属性分析技术&#xff0c;能够快速准确地检测人脸并返回…

Python基础:正则表达式(regular expression)详解

在Python中&#xff0c;正则表达式是一种强大的工具&#xff0c;可用于匹配和操作字符串。什么是正则表达式&#xff1f; 正则表达式是一种模式匹配语言&#xff0c;用于匹配字符串中的特定模式。这些模式可以是字母、数字、字符组合或其他符号。正则表达式通常用于文本处理、网…

机器人制作开源方案 | 守护一体化护耆卫士

作者&#xff1a;白玲玲、张硕、孔亚轩单位&#xff1a;兰州理工大学指导老师&#xff1a;毕广利 1. 场景调研 “探索者”平台是结合机械、电子、传感器、计算机软硬件、控制、人工智能和造型技术等众多的先进技术研发推出的专业型机器人设备原型设计工具&#xff0c;包含机构…

【EI会议征稿】第三届图像,信号处理与模式识别国际学术会议(ISPP 2024)

第三届图像&#xff0c;信号处理与模式识别国际学术会议&#xff08;ISPP 2024) 2024 3rd International Conference on Image, Signal Processing and Pattern Recognition&#xff08;ISPP 2024&#xff09; 第三届图像&#xff0c;信号处理与模式识别国际学术会议&#xf…

Android---网络编程优化

网络请求操作是一个 App 的重要组成部分&#xff0c;程序大多数问题都是和网络请求有关。使用 OkHttp 框架后&#xff0c;可以通过 EventListener 来查看一次网络请求的详细情况。一次完整的网络请求会包含以下几个步骤。 也就是说&#xff0c;一次网络请求的操作是从 DNS 解析…

在node-red 的function中使用第三方的npm 库来处理业务逻辑

首先找到node-red的安装目录,这个目录可以在启动日志里看到。 如我的 我的就是在 /Users/fizz/.node-red 进入该目录,安装所需要的库 如 npm install lodash 然后在setting.js 中配置functionGlobalContext // The following property can be used to seed Global Context …