linux開發之mmap內存映射

mmap概念

mmp是 將文件或設備直接映射到進程的虛擬內存空間 的一種機制,可實現程序像訪問內存一樣訪問文件,而不需要傳統的 read()/write()系統調用

文件內容被映射到進程的地址空間,讀寫文件就像操作內存一樣,操作系統負責自動同步內存和文件的修改(除非顯式禁用)。
好處:

  • 文件 I/O 優化:避免頻繁的 read()/write(),提升性能,例如數據庫引擎(如 SQLite、LevelDB)用 mmap加速磁盤訪問
  • 多個進程需要高效共享數據(如父子進程、獨立進程),比管道、消息隊列更快(直接內存訪問),Chrome 瀏覽器用 mmap共享多個標簽頁的內存,機器學習訓練時,多個進程共享模型參數
  • 序運行時加載動態鏈接庫(.so/.dll)時,庫文件被映射到內存,按需加載(懶加載),節省內存
  • sendfile:文件通過 mmap映射到內存,直接通過 DMA 發送到網卡,無需 CPU 參與拷貝

語法:函數聲明

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
參數說明
addr建議映射的起始地址(通常傳 NULL,由系統自動分配)
length映射區域的長度(字節)
prot內存保護方式(PROT_READ, PROT_WRITE 等)
flags映射類型(MAP_SHARED, MAP_PRIVATE
fd文件描述符(通過 open 獲得)
offset文件映射起始偏移(必須是頁大小的整數倍)

相關常量:

// 保護方式
PROT_READ      // 可讀
PROT_WRITE     // 可寫
PROT_EXEC      // 可執行
PROT_NONE      // 不可訪問// 映射類型
MAP_SHARED     // 修改會寫回文件,進程間共享
MAP_PRIVATE    // 寫時復制,修改不寫回文件// 取消映射
int munmap(void *addr, size_t length);  // 釋放映射

mmap寫文件

[root@prs31 01-fd]# cat 01-mmap_read.c 
// 01-mmap_read.c#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>int main() {int fd;struct stat sb;char *mapped;fd = open("test.txt", O_RDONLY);if (fd == -1) {perror("open");exit(1);}// 2. 獲取文件狀態(主要是大小)if (fstat(fd, &sb) == -1) {perror("fstat");exit(1);}// 3. 映射文件到內存mapped = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);if (mapped == MAP_FAILED) {perror("mmap");close(fd);exit(1);}// 4. 像訪問數組一樣讀取內容printf("文件內容:\n");for (off_t i = 0; i < sb.st_size; i++) {putchar(mapped[i]);     // 逐字符打印內存映射文件(mmap)的內容}// 5. 解除映射if (munmap(mapped, sb.st_size) == -1) {perror("munmap");}close(fd);return 0;
}

在這里插入圖片描述

mmap追加文件內容

[root@prs31 01-fd]# cat 02-mmap_write.c 
// mmap_write.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>int main() {int fd;struct stat sb;char *mapped;const char *new_content = "\nAppended via mmap!";// 1. 以讀寫方式打開文件fd = open("test.txt", O_RDWR);if (fd == -1) {perror("open");exit(1);}// 2. 獲取文件大小if (fstat(fd, &sb) == -1) {perror("fstat");exit(1);}// 3. 擴展文件大小(為追加內容預留空間)off_t new_size = sb.st_size + strlen(new_content);if (ftruncate(fd, new_size) == -1) {perror("ftruncate");close(fd);exit(1);}// 4. 映射整個新大小的文件,這里傳遞使用擴展后的文件大小mapped = mmap(NULL, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (mapped == MAP_FAILED) {perror("mmap");close(fd);exit(1);}// 5. 在原內容末尾寫入新內容,strcpy(目的變量,要添加的變量)strcpy(mapped + sb.st_size, new_content);printf("已追加內容到文件\n");if (munmap(mapped, new_size) == -1) {perror("munmap");}close(fd);return 0;
}

在這里插入圖片描述

mmap實現進程間共享內存

[root@prs31 01-fd]# cat 03-shm_writer.c 
// 03-shm_writer.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>int main() {int fd;char *mapped;// 1. 創建共享文件fd = open("/tmp/shm_file", O_CREAT | O_RDWR, 0644);if (fd == -1) {perror("open");exit(1);}// 2. 擴展文件大小ftruncate(fd, 4096);  // 1頁// 3. 映射mapped = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (mapped == MAP_FAILED) {perror("mmap");exit(1);}// 4. 寫入數據sprintf(mapped, "Hello from Process A (PID: %d)", getpid());printf("寫入: %s\n", mapped);printf("等待按回車繼續...\n");getchar();  // 等待進程B讀取munmap(mapped, 4096);close(fd);return 0;
}

[root@prs31 01-fd]# cat 03-shm_reader.c 
// 03-shm_writer
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>int main() {int fd;char *mapped;fd = open("/tmp/shm_file", O_RDONLY);if (fd == -1) {perror("open");exit(1);}mapped = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);if (mapped == MAP_FAILED) {perror("mmap");exit(1);}printf("讀取到: %s\n", mapped);munmap(mapped, 4096);close(fd);return 0;
}

運行代碼

[root@prs31 01-fd]# gcc 03-shm_writer.c shm_writer
[root@prs31 01-fd]# gcc 03-shm_reader.c shm_reader

在這里插入圖片描述

第二個終端:
在這里插入圖片描述

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

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

相關文章

CPP繼承

繼承 一、繼承概述 1、為什么需要繼承 如下示例&#xff0c;Person 類、Student 類、Teacher 類有大量重復的代碼&#xff0c;造成代碼冗余&#xff0c;降低開發效率。我們可以通過繼承來解決這一問題。在面向對象的編程語言中&#xff0c;繼承是一個核心概念。主要作用將重復的…

模塊 PCB 技術在未來通信領域的創新突破方向

未來通信領域對數據傳輸速率、信號穩定性及設備集成度的要求持續攀升&#xff0c;模塊 PCB 作為通信設備的關鍵組件&#xff0c;其技術創新成為推動行業發展的核心動力。獵板 PCB 憑借深厚的技術積累與持續的研發投入&#xff0c;在模塊 PCB 技術創新方面取得諸多突破&#xff…

mysql的InnoDB索引總結

MySQL InnoDB索引知識點總結 1. 索引類型 1.1 聚簇索引&#xff08;Clustered Index&#xff09; 定義與特性 定義&#xff1a;聚簇索引是InnoDB的默認存儲方式&#xff0c;數據行按照主鍵的順序物理存儲在磁盤上特性&#xff1a; 每個InnoDB表只能有一個聚簇索引數據頁中的記錄…

C++模板的補充

類模板(上一篇沒講到類模板C/C內存管理&函數模板-CSDN博客&#xff09; 類模板的定義&#xff1a; template<class T1, class T2, ..., class Tn> class 類模板名 {// 類內成員定義 }; 用一個簡單的棧例子講類模板 #define _CRT_SECURE_NO_WARNINGS #include &l…

用JOIN替代子查詢的查詢性能優化

一、子查詢的性能瓶頸分析?重復執行成本?關聯子查詢會導致外層每行數據觸發一次子查詢&#xff0c;時間復雜度為O(M*N)sql-- 典型低效案例 SELECT e.employee_id, (SELECT d.department_name FROM departments d WHERE d.department_id e.department_id) FROM employees e; …

【設計模式】訪問者模式模式

訪問者模式&#xff08;Visitor Pattern&#xff09;詳解一、訪問者模式簡介 訪問者模式&#xff08;Visitor Pattern&#xff09; 是一種 行為型設計模式&#xff08;對象行為型模式&#xff09;&#xff0c;它允許你在不修改對象結構的前提下&#xff0c;為對象結構中的元素添…

比特幣現貨和比特幣合約的區別與聯系

一、基本定義項目現貨&#xff08;Spot&#xff09;合約&#xff08;Futures / Perpetual&#xff09;本質直接買賣比特幣本身買賣比特幣價格的衍生品合約所得資產真實的 BTC合約頭寸&#xff08;沒有直接持有 BTC&#xff09;結算方式交割比特幣現金結算&#xff08;多數平臺&…

Qt/C++開發監控GB28181系統/實時監測設備在線離線/視頻預覽自動重連/重新點播取流/低延遲

一、前言說明 一個好的視頻監控系統&#xff0c;設備掉線后能夠自動重連&#xff0c;也是一個重要的功能指標&#xff0c;如果監控系統只是個rtsp流地址&#xff0c;那非常好辦&#xff0c;只需要重新打開流地址即可&#xff0c;而gb28181中就變得復雜了很多&#xff0c;需要多…

此芯p1開發板使用OpenHarmony時llama.cpp不同優化速度對比(GPU vs CPU)

硬件環境 Cix P1 SoC 瑞莎星睿 O6 開發板 rx580顯卡 產品介紹&#xff1a; https://docs.radxa.com/orion/o6/getting-started/introduction OpenHarmony 5.0.0 使用vulkan后端的llama.cpp &#xff08;GPU&#xff09; # ./llama-bench -m /data/qwen1_5-0_5b-chat-q2_k.…

Android 四大布局:使用方式與性能優化原理

一、四大布局基本用法與特點1. LinearLayout&#xff08;線性布局&#xff09;使用方式&#xff1a;<LinearLayoutandroid:orientation"vertical" <!-- 排列方向&#xff1a;vertical/horizontal -->android:layout_width"match_parent"android:…

Redis的BigKey問題

Redis的BigKey問題 什么是大Key問題&#xff1f; 大key問題其實可以說是大value問題&#xff0c;就是某個key對應的value所占據的存儲空間太大了&#xff0c;所以導致我們在操作這個key的時候花費的時間過長&#xff08;序列化\反序列化&#xff09;&#xff0c;從而降低了redi…

TDengine IDMP 產品基本概念

基本概念 元素 (Element) IDMP 通過樹狀層次結構來組織數據&#xff0c;樹狀結構里的每個節點被稱之為元素 (Element)。元素是一個物理的或邏輯的實體。它可以是具體的物理設備&#xff08;比如一臺汽車&#xff09;&#xff0c;物理設備的一個子系統&#xff08;比如一臺汽車的…

專題二_滑動窗口_將x減到0的最小操作數

一&#xff1a;題目解釋&#xff1a;每次只能移除數組的邊界&#xff0c;移除的邊界的總和為x&#xff0c;要求返回你移除邊界的最小操作數&#xff01;也就是說你最少花幾次移除邊界&#xff0c;就能夠讓這些移除的邊界的和為x&#xff0c;則返回這個次數&#xff01;所以這個…

CentOS 7 下通過 Anaconda3 運行llm大模型、deepseek大模型的完整指南

CentOS 7 下通過 Anaconda3 運行llm大模型、deepseek大模型的完整指南A1 CentOS 7 下通過 Anaconda3 運行大模型的完整指南一、環境準備二、創建專用環境三、模型部署與運行四、優化配置常見問題解決B1 CentOS 7 下通過 Anaconda3 使用 CPU 運行 DeepSeek 大模型的完整方案一、…

Flutter應用在Windows 8上正常運行

要讓Flutter應用在Windows 8上正常運行,需滿足以下前提條件,涵蓋系統環境、依賴配置、編譯設置等關鍵環節: 一、系統環境基礎要求 Windows 8版本 必須是 Windows 8.1(核心支持),不支持早期Windows 8(需升級到8.1,微軟已停止對原版Windows 8的支持)。 確認系統版本:右…

Redis實現消息隊列三種方式

參考 Redis隊列詳解&#xff08;springboot實戰&#xff09;_redis 隊列-CSDN博客 前言 MQ消息隊列有很多種&#xff0c;比如RabbitMQ,RocketMQ,Kafka等&#xff0c;但是也可以基于redis來實現&#xff0c;可以降低系統的維護成本和實現復雜度&#xff0c;本篇介紹redis中實現…

【C++動態版本號生成方案:實現類似C# 1.0.* 的自動構建號】

C動態版本號生成方案&#xff1a;實現類似C# 1.0.* 的自動構建號 在C#中&#xff0c;1.0.*版本號格式會在編譯時自動生成構建號和修訂號。本文將介紹如何在C項目中實現類似功能&#xff0c;通過MSBuild自動化生成基于編譯時間的版本號。 實現原理 版本號構成&#xff1a;主版本…

【算法題】:斐波那契數列

用 JavaScript 實現一個 fibonacci 函數&#xff0c;滿足&#xff1a; 輸入 n&#xff08;從0開始計數&#xff09;輸出第 n 個斐波那契數&#xff08;斐波那契數列從 1 開始&#xff1a;1,1,2,3,5,8,13,21…&#xff09; 示例&#xff1a; fibonacci(0) > 1fibonacci(4) &g…

【YOLOv13[基礎]】熱力圖可視化實踐 | 腳本升級 | 優化可視化效果 | 論文必備 | GradCAMPlusPlus, GradCAM, XGradCAM, EigenCAM等

本文將進行添加YOLOv13版本的升級版熱力圖可視化功能的實踐,支持圖像熱力圖可視化、優化可視化效果、 可以選擇使用GradCAMPlusPlus, GradCAM, XGradCAM, EigenCAM, HiResCAM, LayerCAM, RandomCAM, EigenGradCAM。一個參數即可設置是否顯示檢測框等。 原圖 結果圖

ElasticSearch相關術語介紹

1.RESTful風格程序REST(英文全稱為:"Representational State Transfer")指的是一組架構約束條件和原則。它是一種軟件架構風格&#xff08;約束條件和原則的集合&#xff0c;但并不是標準&#xff09;。 REST通過資源的角度觀察網絡&#xff0c;以URI對網絡資源進行…