C++中的内存锁定

      内存锁定(memory locking)是确保进程保留在主内存中并且免于分页的一种方法。在实时环境中,系统必须能够保证将进程锁定在内存中,以减少数据访问、指令获取、进程之间的缓冲区传递等的延迟。锁定内存中进程的地址空间有助于确保应用程序的响应时间满足实时要求。作为一般规则,时间关键的进程(time-critical process)应该被锁定到内存中。
      虚拟地址空间(virtual address space)被划分为固定大小的单元(fixed-sized unit),称为页(page)。每个进程通常占用多个页,这些页在进程执行时独立地移入和移出主内存。通常,当进程执行时,进程页的子集驻留在主内存(primary memory)中。
      由于可用的主内存量是有限的,因此分页通常会牺牲一些页即要移入页,必须移出其他页。如果要替换的页在执行期间被修改,则该页将被写入文件区域。该页根据需要被带回主内存,并且在内核检索该页时延迟执行。
      分页通常对当前进程是透明的通过增加物理内存的大小或将页锁定到内存中可以减少分页量。但是,如果进程非常大或者页频繁调入和调出,则调页所需的系统开销可能会降低效率。
      对于实时应用程序来说,拥有足够的内存比非实时应用程序更重要。实时应用程序必须确保进程被锁定到内存中,并且有足够的内存可供实时进程和系统使用。对于关键的实时任务来说,由于分页引起的延迟通常是不可接受的。
      内存锁定适用于进程的地址空间。只有映射到进程地址空间的页才能被锁定到内存中。当进程退出时,页将从地址空间中删除,并且锁也被删除。
      内存锁定有两个主要应用:实时算法和高安全性数据处理。
      页锁定内存无法从RAM移动到交换文件,确保该内存始终驻留在物理内存中。与传统内存相比,它提高了GPU的PCI-Express(CPU和GPU之间的总线) I/O速度。
      NVIDIA的GPU是一个协处理器(co-processor),GPU内核启动、数据初始化和传输均由CPU进行.
      CUDA中有四种类型的内存分配
      1.Pageable memory(可分页内存):主机中分配的内存默认是可分页内存。该内存位置的数据可供主机使用。为了将此数据传输到设备,CUDA运行时会将此内存拷贝到临时固定内存,然后传输到设备内存。因此,存在两次内存传输。因此,这种类型的内存分配和传输速度很慢。GPU无法直接从可分页主机内存访问数据。涉及的函数:malloc, cudaMalloc, cudaMemcpy
      2.Pinned memory(固定内存):也称为页锁定,数据可以直接在主机固定存储器中初始化。与malloc分配的常规可分页主机内存相反。通过这样做,我们可以避免像可分页内存中那样的两次数据传输。这将使该过程更快,但会牺牲主机性能。当数据在固定存储器中初始化时,主机处理的存储器可用性会降低。涉及的函数:cudaMallocHost, cudaMalloc, cudaMemcpy
      优点:
      (1).对于某些设备,页锁定主机内存和设备内存之间的拷贝可以与内核执行同时执行。
      (2).在某些设备上,页锁定主机内存可以映射到设备的地址空间,从而无需将其拷贝到设备内存或从设备内存中拷贝。
      (3).在具有前端总线(front-side bus)的系统上,如果主机内存被分配为页锁定,则主机内存和设备内存之间的带宽(bandwidth)会更高。
      注:页锁定主机内存不会缓存在非I/O一致Tegra设备上。此外,非I/O一致Tegra设备不支持cudaHostRegister。
      3.Mapped memory(映射内存)或Zero copy memory(零拷贝内存):零拷贝内存是映射到设备地址空间的固定内存。主机和设备都可以直接访问该内存。涉及的函数:cudaHostAlloc, cudaHostGetDevicePointer
      优点:
      (1).当设备内存不足时,可以利用主机内存。
      (2).可以避免主机和设备之间显式的数据传输。
      (3).提高PCI-Express传输速率。
      缺点:由于它被映射到设备地址空间,因此数据不会被拷贝到设备内存中。传输将在执行期间发生,这将大大增加处理时间。
      4.Unified memory(统一内存):这将创建一个托管内存池,其中来自该内存池的每个分配都可以在主机和设备上使用相同的地址或指针进行访问。底层系统将数据迁移到主机和设备。涉及的函数:cudaMallocManaged
      优点:无需为所需的设备显式分配和恢复内存。这降低了编程复杂性。
      缺点:在内存管理方面添加了额外的指令.
      RAM(Random Access Memory):随机存取存储器,是一种计算机存储器,它用于临时存储数据和指令,以便在计算机运行时快速访问。RAM可以随时读取和写入数据,而且读取和写入的速度非常快。相比之下,硬盘、闪存等存储设备的数据访问速度要慢得多。RAM通常用于计算机的主存(内存),以便CPU可以快速访问指令和数据。它也用于缓存和其他高速存储设备,以加快数据访问速度。
      linux下的用于内存锁定的函数mlock/mlockall, munlock/munlockall声明如下:

int mlock(const void *addr, size_t len);
int munlock(const void *addr, size_t len);
int mlockall(int flags);
int munlockall(void);

      mlock:锁定从addr开始并持续len字节的地址范围内的页。当调用成功返回时,所有包含指定地址范围的页都保证驻留在RAM中,直到稍后解锁。
      munlock:解锁从addr开始并持续len字节的地址范围内的页。在此调用之后,包含指定内存范围的所有页都可以由内核再次移动到外部交换空间。
      mlockall:锁定映射到调用进程的地址空间的所有页。This includes the pages of the code, data and stack segment, as well as shared libraries, user space kernel data, shared memory, and memory-mapped files. 当调用成功返回时,所有映射的页都保证驻留在RAM中,直到稍后解锁。
      munlockall:解锁映射到调用进程地址空间的所有页.
      mlock和mlockall函数分别将调用进程的部分或全部虚拟地址空间(virtual address space)锁定到RAM中,防止该内存被分页到交换区域(preventing that memory from being paged to the swap area)。munlock和munlockall执行相反的操作,分别解锁调用进程的部分或全部虚拟地址空间,以便在内核内存管理器(kernel memory manager)需要时可以再次交换指定虚拟地址范围内的分页。
      内存锁定和解锁以整页(whole page)为单位进行
      这些函数调用成功时返回0;失败时返回-1,设置errno来指出错误。
      注意
      1.内存锁定不会被通过fork创建的子进程继承(注:现代的Unix系统可能并非这样)。
      2.如果通过munmap取消映射,则会自动删除地址范围(address range)上的内存锁定。
      3.如果锁定了非常多的内存,有些程序可能会因为缺少内存(real memory)而根本无法运行,或者导致系统运行速度更慢。
      4.内存锁定不堆叠(memory locks do not stack),不能两次锁定特定页。
      5.内存锁定持续存在,直到进程退出或应用程序调用相应的munlock或munlockall函数解锁它为止。
      以上内存主要整理自:

      1.https://man7.org/linux/man-pages/man2/mlock.2.html
      2.https://medium.com/analytics-vidhya/cuda-memory-model-823f02cef0bf
      3.https://www3.physnet.uni-hamburg.de/physnet/Tru64-Unix/HTML/APS33DTE/DOCU_005.HTM
      4.https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#page-locked-host-memory

      在Windows上可使用VirtualAlloc、VirtualLock、VirtualUnlock、VirtualFree函数进行内存锁定。

     以下为测试代码:

int test_memory_locking()
{constexpr size_t size{ 1024 };
#ifdef _MSC_VER// 1. allocate memoryauto p = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);if (p == nullptr) {std::cerr << "Error: VirtualAlloc: " << GetLastError() << "\n";return -1;}// 2. lock memory pageif (!VirtualLock(p, size)) {std::cerr << "Error: VirtualLock: " << GetLastError() << "\n";return -1;}// 3. use lock memory// 4. unlock memory pageif (!VirtualUnlock(p, size)) {std::cerr << "Error: VirtualUnlock: " << GetLastError() << "\n";return -1;}// 5. free memoryif (!VirtualFree(p, 0, MEM_RELEASE)) {std::cerr << "Error: VirtualFree: " << GetLastError() << "\n";return -1;}
#elsechar data[size];// 1. get configuration information at run timeauto page_size = sysconf(_SC_PAGE_SIZE);if (page_size == -1) {std::cerr << "Error: sysconf: " << strerror(errno) << "\n";return -1;}std::cout << "page size: " << page_size << "\n";// 2. lock memory pageif (mlock(data, size) == -1) {std::cerr << "Error: mlock: " << strerror(errno) << "\n";return -1;}// 3. use lock memory// 4. unlock memory pageif (munlock(data, size) == -1) {std::cerr << "Error: munlock: " << strerror(errno) << "\n";return -1;}
#endifreturn 0;
}

      执行结果如下图所示:

      GitHub:https://github.com/fengbingchun/Messy_Test

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 1954. 收集足够苹果的最小花园周长

一、题目 1、题目描述 给你一个用无限二维网格表示的花园&#xff0c;每一个 整数坐标处都有一棵苹果树。整数坐标 (i, j) 处的苹果树有 |i| |j| 个苹果。 你将会买下正中心坐标是 (0, 0) 的一块 正方形土地 &#xff0c;且每条边都与两条坐标轴之一平行。 给你一个整数 need…

DevC++ 用C语言的多线程 实现简单的客户端和服务器

知识来源一&#xff1a; 使用Dev-C实现简单的客户端和服务器-CSDN博客 此先生的博客使用的是win32 SDK来创建多线程&#xff0c;然后鄙人对这个版本的多线程细节不明。于是又重新用C语言的线程替代win32API,以此继续学习服务器代码。 知识来源二&#xff1a;DevC 多线程创建…

Windows 11中显示文件扩展名的方法与Windows 10大同小异,但前者更人性化

默认情况下&#xff0c;Windows 11会隐藏已知文件类型的文件扩展名。这可能会使在不首先打开文件的情况下很难识别文件类型。 幸运的是&#xff0c;你可以将Windows 11配置为显示已知文件类型的扩展名。该方法类似于Windows 10&#xff0c;但该选项现在组织在下拉菜单中&#…

在线客服系统:解决常见问题的实用工具与解决方案

市场得不断发展促使着消费者服务意识的觉醒&#xff0c;越来越多的消费者在购买产品的时候不仅看产品的功能、外观、性能&#xff0c;还关注品牌的服务质量。在线客服系统的出现帮助企业解决了客户服务难的问题。接下来&#xff0c;我们具体聊一聊在线客服系统能解决哪些问题&a…

BTF:实践指南

本文地址&#xff1a;BTF&#xff1a;实践指南 | 深入浅出 eBPF 1. BPF 的常见限制 1.1 调试限制1.2 可移植性2. BTF 是什么&#xff1f;3. BTF 快速入门 3.1 BPF 快速入门3.1 BTF 和 CO-RE4. 结论 BPF 是 Linux 内核中基于寄存器的虚拟机&#xff0c;可安全、高效和事件驱动…

Bresenham 算法

1965 年&#xff0c;Bresenham 为数字绘图仪开发了一种绘制直线的算法&#xff0c;该算法同样使用于光栅扫描显示器&#xff0c;被称为 Bresenham 算法。 原理 算法的目标是选择表示直线的最佳光栅位置。Bresenhan 算法在主位移方向上每次递增一个单位。另一个方向的增量为 0…

浅谈Redis分布式锁(下)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 自定义Redis分布式锁的…

分布式核心技术之分布式共识

文章目录 什么是分布式共识&#xff1f;分布式共识方法PoWPoSDPoS 三种分布式共识算法对比分析 选主过程就是一个分布式共识问题&#xff0c;因为每个节点在选出主节点之前都可以认为自己会成为主节点&#xff0c;也就是说集群节点“存异”&#xff1b;而通过选举的过程选出主节…

Qt 开源项目

Qt 开源项目 Omniverse View链接技术介绍 QuickQanava链接技术介绍QField链接技术介绍 AtomicDEX链接技术介绍 Status-desktop链接技术介绍 Librum链接技术介绍 A Simple Cross-Platform ReaderQPrompt链接技术介绍 GCompris链接技术介绍 Scrite链接技术介绍 QSkinny链接技术介…

【LeetCode】链表精选11题

目录 快慢指针&#xff1a; 1. 相交链表&#xff08;简单&#xff09; 2. 环形链表&#xff08;简单&#xff09; 3. 快乐数&#xff08;简单&#xff09; 4. 环形链表 II&#xff08;中等&#xff09; 5. 删除链表的倒数第 N 个节点&#xff08;中等&#xff09; 递归迭…

burpsuite与sqlmap联动(sqlipy配置)

首先我们需要在burpsuite的 扩展-选项 里配置两个路径&#xff1a; 第一个路径为 jython-standalone-2.7.3.jar 的路径 这个jar文件我们需要自己下载&#xff0c;下载地址&#xff1a;https://www.jython.org/ 点击 download 点击 Jython Standalone 下载好之后将这个jar文件…

一个非常实用的Python SSH库

前言 Python的Paramiko库&#xff0c;它是一个用于实现SSHv2协议的客户端和服务器的库。通过使用Paramiko&#xff0c;我们可以在Python程序中轻松地实现远程服务器的管理、文件传输等功能。特别做智能硬件产品的同学要熟悉它&#xff0c;因为它能为你减少很多麻烦&#xff0c…