[Linux]mmap()函數內存映射原理及用法

一、內存映射

內存映射,簡而言之就是將用戶空間的一段內存區域映射到內核空間,映射成功后,用戶對這段內存區域的修改可以直接反映到內核空間,同樣,內核空間對這段區域的修改也直接反映用戶空間。那么對于內核空間和用戶空間兩者之間需要大量數據傳輸等操作的話效率是非常高的。
以下是一個把普遍文件映射到用戶空間的內存區域的示意圖:
示意圖


二、mmap函數

1.基本介紹

mmap是一種內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。
實現這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用read,write等系統調用函數。相反,內核空間對這段區域的修改也直接反映用戶空間,從而可以實現不同進程間的文件共享。如下圖所示:
示意圖

2.mmap的優勢

通過系統調用mmap ,程序可以高效地訪問文件數據,而無需通過傳統的readwrite系統調用進行數據的復制,具體來說為:

  • 傳統的readwrite分為兩步(下面以write為例)
    • 第一步:用戶態空間緩沖區 → 內核頁緩沖區(其實就是內核文件緩沖區)
    • 第二步:內核頁緩沖區 → 磁盤
  • 使用mmap
    • 映射階段:內核將文件映射到進程的虛擬地址空間,但物理內存尚未分配(這是延遲申請,當真正訪問階段需要的時候才缺頁中斷分配)
    • 修改數據:進程直接修改映射的內存(相當于直接修改內核的頁緩存),無需調用 write,也無用戶態到內核態的數據拷貝

注意:當內核頁緩存修改好了,我們就認為改好了,我們不關心內核緩沖區到磁盤的刷新這一過程(復雜)


三、mmap接口介紹

當我們建立好映射以后,就可以直接對“開辟”的空間進行操作(虛擬地址)
我們對虛擬地址的操作,都是直接修改映射的內存。

1. mmap建立映射

頭文件<sys/mman.h>
函數原型

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

參數說明

  • addr:建議的映射起始地址(通常設為NULL,由內核自動選擇)
  • length:映射區域的長度(必須是頁大小(4 KB)的整數倍,如4096字節)
  • prot:映射區的內存保護模式選項(用|鏈接)
    • PROT_READ:映射區可讀
    • PROT_WRITE:映射區可寫
    • PROT_EXEC:映射區可執行
    • 注意:映射權限必須<=文件打開權限
  • flags:映射類型(如MAP_SHARED MAP_PRIVATE
    • MAP_PRIVATE:創建?個私有映射。對映射區域的修改不會反映到底層文件中。(即:修改僅對當前進程有效(寫時復制,類似 fork
    • MAP_SHARED:創建?個共享映射。對映射區域的修改會反映到底層文件中(即:修改會同步到文件,其他進程可見)
    • MAP_ANONYMOUS:指定要創建?個匿名內存映射
  • fd:文件描述符(匿名映射時設為 -1)
  • offset:文件偏移量(開始映射的位置相較于0位置處的偏移)(必須是頁大小的整數倍)

返回值

  • 成功:返回映射區的起始地址(虛擬地址)
  • 失敗:返回(void*) -1 或者 MAP_FAILED(等效的)

注意

  • 映射的要是一個已經打開的文件!
  • 文件大小為0的文件無法映射,需要先調整文件大小
    • ftruncate(fd, SIZE)(會把文件的內容全部初始化成\0
  • 映射的長度如果 > 文件的大小,則可能導致未定義行為
  • 因為mmap需要讀取文件元數據(如大小):所以,即使你只需要寫入權限,也需要在open文件的時候賦予讀權限

2.munmap取消映射

函數原型

int munmap(void *addr, size_t length);

參數介紹

  • addr:映射空間的起始地址
  • length:空間長度(大小)

返回值

  • 成功:0
  • 錯誤:-1(錯誤碼會被設置)

四、mmap的用法

1.寫入映射

#include<iostream>
#include<cstdio>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>#define FILENAME "log.txt"
#define SIZE 1024int main()
{//open fileint fd = open(FILENAME, O_RDWR|O_APPEND|O_CREAT, 0666);if (fd < 0){perror("open");return 1;}// 調整file sizeftruncate(fd, SIZE);//建立映射/*void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);*/char* mmap_addr = (char*)mmap(nullptr, SIZE, PROT_WRITE, MAP_SHARED, fd, 0);if (mmap_addr == MAP_FAILED){perror("mmap");return 2;}//寫入操作for (int c = 'a', i = 0; c <= 'z'; c++, i++){mmap_addr[i] = c;}//取消映射munmap(mmap_addr, SIZE);//關閉文件close(fd);std::cout << "寫入映射完畢" << std::endl;return 0;
}

2.讀取映射

#include<iostream>
#include<cstdio>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>#define FILENAME "log.txt"int main()
{//open fileint fd = open(FILENAME, O_RDONLY);if (fd < 0){perror("open");return 1;}struct stat st; // struct stat 類型的結構體用于記錄文件的屬性fstat(fd, &st);//建立映射char* mmap_addr = (char*)mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);if (mmap_addr == MAP_FAILED){perror("mmap");return 2;}//讀取操作std::cout << mmap_addr << std::endl;//取消映射munmap(mmap_addr, st.st_size);//關閉文件close(fd);std::cout << "讀取映射完畢" << std::endl;return 0;
}

3.簡單模擬實現malloc

在malloc里,對應大塊的內存通常是使用mmap來分配的,而對應小塊的內存,是用brk來分配的。

這里要再介紹一個flags選項:MAP_ANONYMOUS

  • MAP_ANONYMOUS:指定要創建?個匿名內存映射
  • 當使使用MAP_ANONYMOUS 標志時,mmap會分配?段不與任何?件相關聯的內存區域(即這段內存沒有?件作為其后端存儲)。
  • 這種類型的映射通常用于需要分配私有內存的場景,例如進程內部的內存分配

下面用mmap簡單模擬實現一下malloc

#include<iostream>
#include<cstdio>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>#define SIZE 1024void* MyMalloc(int size)
{//建立映射(匿名映射)--- 可讀可寫void* mmap_addr = mmap(nullptr, size, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_ANONYMOUS, -1, 0);if (mmap_addr == MAP_FAILED){perror("mmap");exit(EXIT_FAILURE);}return mmap_addr;
}void* MyFree(void* mmap_addr, int size)
{if(munmap(mmap_addr, size) == -1){perror("munmap");exit(EXIT_FAILURE);}
}int main()
{char* ptr = (char*)MyMalloc(SIZE);//寫入for (int c = 'a', i = 0; c <= 'z'; c++, i++){ptr[i] = c;}//讀取std::cout << "寫入后的addr content: " << ptr << std::endl;MyFree(ptr, SIZE);return 0;
}

4.makefile

.PHONY:all
all:write read malloc
write:mmap_write.ccg++ -o $@ $^ -std=c++11
read:mmap_read.ccg++ -o $@ $^ -std=c++11
malloc:mmap_malloc.ccg++ -o $@ $^ -std=c++11.PHONY:clean
clean:rm -f write read malloc

5.最終結果

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/88792.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/88792.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/88792.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

通信無BUG,ethernet ip轉profinet網關,汽車焊接設備通信有心機

在運用“激光釬焊”對汽車車頂、側面板、后行李箱蓋等位置進行接合時&#xff0c;必須配備能夠沿著復雜車身線條&#xff0c;對細窄焊接線實施高精度快速檢測及模仿控制的“焊縫跟蹤控制”。 那么汽車生產線的系統升級改造迫在眉睫&#xff0c;當西門子PLC和庫卡機器人無法通信…

python腳本ETH獲取最新發行版本并將是否更新信息發送到釘釘

import requests import json import time import hmac import hashlib import base64 import urllib.parse# 1. 配置釘釘機器人 webhook "https://oapi.dingtalk.com/robot/send?access_tokenXXX" secret "XXX" # 如果沒有加簽驗證&#xff0c;請設…

【Docker基礎】Docker容器管理:docker ps及其參數詳解

目錄 1 docker ps命令概述 1.1 命令定位與作用 1.2 命令基本語法 2 基礎參數詳解 2.1 默認輸出解析 2.2 核心參數解析 2.2.1 -a, --all 2.2.2 -q, --quiet 2.2.3 --no-trunc 3 高級過濾與格式化 3.1 過濾器(--filter)詳解 3.1.1 常用過濾條件 3.1.2 實際應用示例 …

應急響應-感染Neshta病毒

病毒確定&#xff1a; 根據感染現象確定為Virus/Win32.Neshta家族病毒 病毒表現&#xff1a; 該病毒為感染式病毒。該病毒會在系統%SystemRoot%目錄下釋放svchost.com文件&#xff0c;并通過添加注冊表的方式確保每個exe文件執行的時候都會先執行這個文件。該病毒還會收集系統信…

Hyperledger Fabric 入門筆記(二十)Fabric V2.5 測試網絡進階之Tape性能測試

文章目錄 前言一、介紹二、架構三、安裝說明四、使用方法4.1. 修改配置文件4.2. 啟動測試網絡4.3. 運行測試 前言 本文介紹由Hyperledger中國技術工作組提供的另一款區塊鏈網絡性能測試工具Tape的架構、安裝和在Fabric測試網絡中的使用。 一、介紹 Tape是一款輕量級的、可以快…

怎樣在 VS Code 中快速創建 Vue 單文件組件(SFC)的基礎模板結構?

問題 在Vue項目的開發中&#xff0c;我們經常遇到一個問題&#xff0c;創建新組件時要自己輸入基本的框架&#xff0c;比如&#xff1a; <template><div class"page-box"></div> </template><script> export default {name: ,data()…

高防IP在服務器中的作用都有哪些?

高防IP作為一種通過技術手段讓用戶網絡服務更加安全的一種IP地址&#xff0c;有著更高的防御能力&#xff0c;有著強大的流量清洗中心和防御系統&#xff0c;幫助企業實時監控網絡流量&#xff0c;將惡意的用戶請求識別并過濾掉&#xff0c;保護目標服務器不會受到網絡攻擊&…

實戰 X-AnyLabeling:構建高效自動標注系統的工程實踐

文章目錄 一、項目背景與目標二、系統架構與模塊劃分2.1 模塊組成說明2.2 架構圖 三、模型封裝與平臺對接3.1 模型封裝接口3.2 接入 X-AnyLabeling 平臺 四、可視化與預測驗證4.1 UI 預測標簽預覽 五、性能優化與工程經驗5.1 模型加速與推理優化5.2 經驗總結5.3 實際效果 本文將…

UC3842/UC3843反激教程教學開關電源 反激設計步驟,每一關鍵元器件計算

資料下載地址&#xff1a;UC3842/UC3843反激教程教學開關電源 反激設計步驟&#xff0c;每一關鍵元器件計算 1、原理圖 2、PCB圖 3、變壓器設計資料 4、開關電源設計資料 5、主要元器件說明書 6、系統整體資料 7、說明文檔 7.1、電源設計概述 電源規格&#xff1a;設計一款 2…

Docker 入門教程(二):Docker 的基本原理

文章目錄 &#x1f433; Docker 入門教程&#xff08;二&#xff09;&#xff1a;Docker 的基本原理1. Docker 架構總覽&#xff1a;三大核心角色2. 鏡像與容器的關系3. 容器啟動流程&#xff1a;docker run 背后發生了什么&#xff1f; &#x1f433; Docker 入門教程&#xf…

21.安卓逆向2-frida hook技術-HookOkHttp的攔截器

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 內容參考于&#xff1a;圖靈Python學院 工具下載&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取碼&#xff1…

小程序入門:swpier 和 swpier-item 的基本使用

在前端開發中&#xff0c;創建交互式的用戶界面組件是至關重要的。今天&#xff0c;我們將深入探討 swpier 和 swpier-item 的基本使用方法&#xff0c;這兩個組件在構建輪播圖等滑動效果的場景中非常實用。 一、swpier 組件概述 swpier 組件是實現滑動效果的核心容器。它負責…

SQL學習筆記4

約束 1、約束 約束&#xff0c;是指作用在表中字段上的規則&#xff0c;用于限制字段輸入的數據&#xff0c;使得表格式統一&#xff0c;數據內容正確。同一個字段的約束可以有多個 約束包括&#xff1a; 非空約束&#xff0c;限制表中的值不為null:not null 唯一約束&…

力扣刷題(第七十天)

靈感來源 - 保持更新&#xff0c;努力學習 - python腳本學習 比特位計數 解題思路 對于任意整數 x&#xff0c;其 1 的個數等于 x // 2 的 1 的個數加上 x % 2。狀態轉移方程&#xff1a;dp[x] dp[x // 2] (x % 2)。 class Solution:def countBits(self, n: int) ->…

鴻蒙網絡編程系列56-倉頡版通過數據包結束標志解決TCP粘包問題

1. TCP粘包問題解決思路 在本系列的上一篇文章演示了TCP數據粘包的原因以及可能的解決方法&#xff0c;本文將通過其中的添加數據包結束標志的方法來解決這個問題。我們知道&#xff0c;數據粘包的原因是因為發送的時候沒有標明數據包的邊界&#xff0c;那么&#xff0c;我們人…

Redis網絡通信模塊深度解析:單線程Reactor到多線程IO的架構演進

一、核心架構&#xff1a;單線程Reactor模型 Redis網絡模塊采用經典Reactor模式&#xff0c;核心流程如下&#xff1a; void aeMain(aeEventLoop *eventLoop) {while (!eventLoop->stop) {// 前置鉤子&#xff08;集群心跳/數據持久化&#xff09;if (eventLoop->befor…

PILCO: 基于模型的高效策略搜索方法原理解析

PILCO: 基于模型的高效策略搜索方法原理解析 PILCO (Probabilistic Inference for Learning Control) 是一種基于模型的強化學習算法&#xff0c;由Marc Deisenroth和Carl Rasmussen于2011年提出。該算法在數據效率方面表現出色&#xff0c;能夠以極少的樣本數據實現有效學習。…

大語言模型訓練中的自監督學習和其他訓練方式

大語言模型訓練中的自監督學習和其他訓練方式。 自監督學習&#xff08;Self-Supervised Learning&#xff09; 1. 什么是自監督學習&#xff1f; 自監督學習是一種不需要人工標注數據的訓練方式&#xff0c;模型從數據本身學習特征和模式。 在語言模型中的具體實現&#x…

[mcp-servers] 工具與資源 | 模型上下文協議MCP | 錨點分類

第三章&#xff1a;工具與資源 歡迎回來&#xff01; 在之前的旅程中&#xff0c;我們認識了客戶端&#xff08;第一章&#xff1a;客戶端&#xff09;——AI的信使組件 以及MCP服務器&#xff08;第二章&#xff1a;MCP服務器&#xff09;——接收請求并具備執行能力的智能助…

2025年06月27日Github流行趨勢

項目名稱&#xff1a;edit 項目地址 url&#xff1a;https://github.com/microsoft/edit項目語言&#xff1a;Rust歷史 star 數&#xff1a;10807今日 star 數&#xff1a;411項目維護者&#xff1a;lhecker, DHowett, b6k-dev, rhysd, MingcongBai項目簡介&#xff1a;我們都編…