MMAP和madvise的配套使用

Linux内核页表映射实战:从4KB到1GB大页的性能优化指南 本文深入探讨Linux内核页表映射机制,从4KB到1GB大页的性能优化实践。通过分析页表结构、TLB压力等性能瓶颈,提供透明大页(THP)配置、静态大页预留等实战方案,并结合数据库、DPDK网络等场景展示优化效果,帮助系统管理员显著提升内存子系统效率。 阅读详情


https://blog.youkuaiyun.com/bingqingsuimeng/article/details/8133529

本人做流媒体开发的,工作中需要将mpg文件转化成一定格式发送到网络,由于文件太大,程序用mmap()来实现文件的读取,但在实测过程中发现一个大问题,如下: 

服务器配置: 
CPU:两颗至强3.0 
内存:2G 
磁盘:3个SATA硬盘组成磁盘阵列 

测试时同时运行30个播放程序读取30个不同的mpg文件,程序起初运行画面播放非常流畅,几分钟过后,内存剩下15MB左右时,mmap()就开始不停 的进行页面置换,将新的数据读入内存,老的数据置换出去,这时的磁盘利用率不到1%,但CPU耗在iowait上的时间却有90%多 

各位大侠我该怎么办,如果不用内存映射还有没有其他的办法处理大文件???


开个4G的swap分区挂上去试试看 
或者,把文件分段mmap(),如100M的文件做10次mmap(),并且要求在播放1段完前做好下段准备工作

你挂mmap不释放怎么行. 
你mmap一个大文件, 要在这个大文件播放完后才能释放. 
要把大文件分小

你可以分段映射试试看,比如一次映射2M,并跟踪程序在这个映射内的使用情况,如果这此映射的数据快用完时,就提前映射下一段.在上一段用完后,就释放掉其映射.

今天又做了一下测试,先映射整个文件,在使用过程中一段一段释放,还是阻塞在IOWait,另外挂载4G交换分区的方法也试了,效果更差 
      在国外论坛上看了些IOWait的东东,有很多都说红帽企业版+Xeons处理器+磁盘阵列容易发生IOWait,和我现在的配置一模一样,用单独的大文件拷贝就能测得出来,明天下个新内核编译一下试试看

问题已解决,好高兴^_^ 

问题原因: 
    调用mmap()时内核只是建立了逻辑地址到物理地址的映射表,并没有映射任何数据到内存。 
    在你要访问数据时内核会检查数据所在分页是否在内存,如果不在,则发出一次缺页中断,linux默认分页为4K,可以想象读一个将近2G的电影文件要发生多少次中断,I can't bear it!!! 

解决办法: 
    将madvise()和mmap()搭配起来使用,在使用数据前告诉内核这一段数据我要用,将其一次读入内存,现在程序可以并发150个数据流了,每秒最高可读70MB数据 
  

感谢大家的支持,另外还要特别感谢老兵哥在“timer frequency”问题上的支持,那个问题还有待研究,周末了,祝大家愉快。

++++++++++++++++++++++++++++++++++++++++++++++++++++++

 今天在封装一个"内存映射文件"读取的类。编写WINDOWS版本的时候发现CreateFile()函数中,可以在参数dwFlagsAndAttributes中指定FILE_FLAG_SEQUENTIAL_SCAN来优化顺序读的情况。那么,在LINUX中如何优化顺序读呢?
   查了一下资料,发现madvise()这个函数可以对映射的内存提出使用建议,从而提高内存。
   以下是我进行对比测试的代码,可以明显的发现:使用MADV_SEQUENTIAL标志比使用MADV_RANDOM标志更快。

   以下是代码:
=============================================================
//test_advise.cpp
//测试madvise()函数的差异
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <time.h>
#include <sys/time.h>

#ifndef P
#define P(format, ...) do \
    { \
        fprintf(stdout, "%s %s %d " format "\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
        fflush(stdout); \
    } \
    while (0);
#endif

static int operator-(struct timeval& lsh, struct timeval& rsh)
{
    if (lsh.tv_sec==rsh.tv_sec)
    {
        return lsh.tv_usec - rsh.tv_usec;
    }
    else
    {
        return (lsh.tv_sec-rsh.tv_sec)*1000000 + (lsh.tv_usec - rsh.tv_usec);
    }
}

#define FILE_LEGNTH (200*1024*1024)    /*200MB的文件*/

/// 创建一个大的空文件
void CreateFile()
{
    int fd = open("test.dat", O_CREAT | O_RDWR);
    if (fd<1)
    {
        P("open error");
        return;
    }
    lseek(fd, FILE_LEGNTH-1, SEEK_SET);
    write(fd, "\0", 1);
    close(fd);
    fd = -1;
}

/// 顺序读
void SequenceRead()
{
    int fd = open("test.dat", O_RDWR | O_EXCL);
    if (-1==fd)
    {
        P("open error");
        return;
    }
    void* p = mmap(NULL, FILE_LEGNTH, PROT_READ, MAP_SHARED, fd, 0);
    if (MAP_FAILED==p)
    {
        P("map error");
        return;
    }
    close(fd);
    fd = -1;
    //内存使用建议
    if (-1==madvise(p, FILE_LEGNTH, MADV_WILLNEED | MADV_SEQUENTIAL))
    {
        P("madvise error");
        return;
    }
    //下面开始逐个字符读取
    struct timeval start;
    struct timeval end;
    int i;
    unsigned char* pTemp = (unsigned char*)p;
    int nSum = 0;
    gettimeofday(&start, NULL);
    for (i=0; i<FILE_LEGNTH; i++)
    {
        nSum += *pTemp;
        pTemp++;
    }
    gettimeofday(&end, NULL);
    //
    if (-1==munmap(p, FILE_LEGNTH))
    {
        P("unmap error");
        return;
    }
    //显示占用时间
    struct tm stTime;
    localtime_r(&start.tv_sec, &stTime);
    char strTemp[40];
    strftime(strTemp, sizeof(strTemp)-1, "%Y-%m-%d %H:%M:%S", &stTime);
    printf("start=%s.%07d\n", strTemp, (int)start.tv_usec);
    //
    localtime_r(&end.tv_sec, &stTime);
    strftime(strTemp, sizeof(strTemp)-1, "%Y-%m-%d %H:%M:%S", &stTime);
    printf("end =%s.%07d\n", strTemp, (int)end.tv_usec);
    printf("spend=%d 微秒\n", end-start);
}

/// 随机读
void RandomRead()
{
    int fd = open("test.dat", O_RDWR | O_EXCL);
    if (-1==fd)
    {
        P("open error");
        return;
    }
    void* p = mmap(NULL, FILE_LEGNTH, PROT_READ, MAP_SHARED, fd, 0);
    if (MAP_FAILED==p)
    {
        P("map error");
        return;
    }
    close(fd);
    fd = -1;
    //内存使用建议
    if (-1==madvise(p, FILE_LEGNTH, MADV_RANDOM))
    {
        P("madvise error");
        return;
    }
    //下面开始逐个字符读取
    struct timeval start;
    struct timeval end;
    int i;
    unsigned char* pTemp = (unsigned char*)p;
    int nSum = 0;
    gettimeofday(&start, NULL);
    for (i=0; i<FILE_LEGNTH; i++)
    {
        nSum += *pTemp;
        pTemp++;
    }
    gettimeofday(&end, NULL);
    //
    if (-1==munmap(p, FILE_LEGNTH))
    {
        P("unmap error");
        return;
    }
    //显示占用时间
    struct tm stTime;
    localtime_r(&start.tv_sec, &stTime);
    char strTemp[40];
    strftime(strTemp, sizeof(strTemp)-1, "%Y-%m-%d %H:%M:%S", &stTime);
    printf("start=%s.%07d\n", strTemp, (int)start.tv_usec);
    //
    localtime_r(&end.tv_sec, &stTime);
    strftime(strTemp, sizeof(strTemp)-1, "%Y-%m-%d %H:%M:%S", &stTime);
    printf("end =%s.%07d\n", strTemp, (int)end.tv_usec);
    printf("spend=%d 微秒\n", end-start);
}

int main()
{
    CreateFile();
    RandomRead();
    SequenceRead();
    return 1;
}

/*
g++ -o test_advise.o -c test_advise.cpp -g -Wall -Werror
g++ -o test_advise test_advise.o
*/
=============================================================

     需要注意的是,当没有使用madvise的时候,相当于使用madvise(... MADV_NORMAL),这种情况下仍然会进行预读,性能和使用madvise(... MADV_SEQUENTIAL)差不多。我猜想,使用MADV_SEQUENTIAL标志的时候,对于实际的物理内存的占用将是最小的,关于这点,希望内核高手能够给我些指点,谢谢!

Linux内核内存管理总结 微信公众号:奔跑吧linux社区 加奔跑吧微信群请先加微信:runninglinuxkernel欢迎订阅奔跑吧配套旗舰篇视频节目:https://weidian.com/?userid=1352872851 这篇对《奔跑吧Linux内核》第一版的内存管理 做了很棒的笔记和总结。《奔跑吧Linux内核》第一版各大书店有售。 这篇文章作者是:Arnold Lu@南京 原文:https://www.cnblogs.com/arnoldlu/p/8051674.html?from=groupmessage . 阅读详情

相关推荐

2024年C/C++开发者如何通过重学操作系统构建技术护城河

操作系统是计算机系统的核心基石,它管理着进程、线程、内存和文件系统等关键资源,是上层应用高效稳定运行的保障。理解其工作原理,能帮助开发者穿透各种框架和抽象层,直击系统性能瓶颈的本质。在技术快速迭代的今天,这种底层能力正成为区分普通开发者和核心架构师的关键。无论是排查高CPU占用、内存泄漏,还是优化容器化性能、设计高并发服务,都离不开对操作系统机制的深刻把握。掌握进程模型、线程同步、内存管理等核心知识,并能熟练运用GDB、strace、perf等工具进行调试与性能剖析,将使开发者在面对云原生、高性能计算等现代

316

madvise()详解

madvise() 函数建议内核,在从 addr 指定的地址开始,长度等于 len 参数值的范围内,该区域的用户虚拟内存应遵循特定的使用模式。内核使用这些信息优化与指定范围关联的资源的处理和维护过程。如果使用 madvise() 函数的程序明确了解其内存访问模式,则使用此函数可以提高系统性能。 #include #include int madvise(caddr_t addr, siz

wenjieky的专栏 3万+

C++20高性能NLP词表系统:面向嵌入式与实时场景的零拷贝设计

词表(Vocabulary)是NLP流水线中连接文本与模型的关键基础设施,其加载效率、查找性能与内存行为直接影响端到端延迟与资源占用。传统Python实现虽生态丰富,但在车载语音、边缘设备等资源受限场景下,常因GIL锁、动态内存分配、字符串深拷贝及ABI不稳定性引发OOM、毛刺和启动超时。现代C++17/20凭借std::string_view零拷贝视图、constexpr编译期计算、pmr内存池与mmap内存映射等特性,可构建确定性延迟、低内存抖动、高并发安全的只读词表二进制镜像。本文聚焦工业级落地实践,

weixin_33985507的博客 477

Linux基础 -- 内存调优之 madvise 系统调用介绍

linux 内存调优 madvise

sz66cm 学习随笔 5727

统计语言模型实战:低延迟、可解释、轻量级NLP落地指南

统计语言模型(SLM)是自然语言处理的基础概率建模方法,通过n-gram频率统计与平滑技术(如Kneser-Ney)刻画词序列的联合分布,其核心价值在于确定性计算、零依赖部署与原子级可解释性。在边缘计算、小样本领域适配、金融合规审查等强约束场景中,SLM展现出神经网络难以替代的技术优势:无需GPU即可运行于ARM工控设备,不依赖大规模标注数据,且能直接追溯低概率输出至具体语料共现证据。本文聚焦工程落地,详解语料清洗陷阱、内存优化的Trie结构、动态n-gram选择、二进制序列化及线上监控体系,覆盖从政务热线

weixin_30878501的博客 1057

Candle Rust机器学习库:极简设计与边缘推理实践

张量计算是现代机器学习的底层基石,其内存管理、设备调度与计算图构建方式直接决定模型在边缘、嵌入式及WASM等受限环境中的可行性。Candle以Rust语言实现零拷贝张量视图、显式设备调度和静态单向DAG计算图,将内存确定性、编译时可预测性与硬件级优化(如AVX2/NEON量化kernel)深度结合。这种设计不仅规避了Python解释器开销与CUDA隐式状态风险,更使GGUF模型加载、Q4_K_M量化推理与无锁KV Cache管理成为轻量CLI工具、桌面应用及实时控制系统的可靠选择。本文聚焦Candle在资源

weixin_33681778的博客 509

madvise()函数的解析

是一个用于向操作系统提供内存使用建议的系统调用(主要在 Linux 和类 Unix 系统中),目的是优化内存管理策略,从而提升程序性能。它允许应用程序告知内核某块内存区域的预期访问模式,内核会根据这些建议调整预读、缓存、分页等行为。)是 Linux 特有,其他系统(如 BSD)可能支持不同选项。,可以在处理大内存、文件映射或实时性要求高的场景中显著优化性能。内核可能忽略建议,具体行为取决于实现。通常需要按页对齐,否则可能失败(

qq_55655082的博客 1071

YOLOv8s模型在RK3566上的端到端剪枝与部署实战

深度学习模型部署不仅是将PyTorch转为ONNX或加载到推理引擎,更是面向硬件约束、业务SLA和IT运维规范的系统工程。其核心原理在于:模型性能由运行时环境(CPU/NPU架构、内存带宽、驱动版本)与任务特性(如目标检测的mAP敏感性、实时性要求)共同决定;技术价值体现在以可量化方式平衡精度、延迟、功耗与可维护性;典型应用场景包括工业质检、边缘终端和离线AI应用;而剪枝作为关键优化手段,必须从结构化设计、分层调控与NPU适配出发,避免非结构化稀疏带来的实际性能损失。本文聚焦YOLOv8s在RK3566平台

weixin_33785108的博客 352

全志T507-H平台Linux-RT实时性能优化实践

实时操作系统(RTOS)是嵌入式开发中的核心技术,通过Linux-RT补丁可将标准Linux改造为实时系统。其核心原理是通过完全可抢占内核、高精度定时器和CPU隔离机制,将中断响应时间压缩到微秒级。在工业自动化、车载电子等领域,这种实时性能对运动控制、传感器采集等关键任务至关重要。以全志T507-H国产平台为例,通过GPIO寄存器直接映射、中断负载均衡等技术,实测达到14微秒的中断响应延迟。该方案不仅满足PLC控制、雷达信号处理等场景的严苛要求,更为国产芯片在实时应用中的性能验证提供了重要参考。

weixin_34218579的博客 522

AI调用量下降真相:从公有云API到私有化推理的基建转型

大模型推理已从‘能跑’迈入‘稳、省、可控’新阶段,AI调用量变化本质是基础设施范式迁移——当通用API遭遇成本不可持续、安全合规刚性约束与国产硬件适配深水挑战,企业正系统性将流量导向私有化推理集群。这一过程涉及API网关动态路由、国产卡全栈优化、GPU级算力调度、HBM带宽治理及算力成本精细化核算等关键技术环节。AI调用量并非萎缩,而是由表层调用指标转向底层资源效能指标;国产化替代也不止于换芯,更在于构建可审计、可追溯、可优化的自主推理基座。本文聚焦AI基础设施落地中的七层关键架构与实操反模式,为技术负责人

weixin_33737134的博客 471

第 18 章:ART 运行时

Android运行时(ART)是Android应用的执行环境,负责加载和执行DEX字节码。ART通过多层级编译策略(解释器、JIT、AOT)和并发垃圾回收(如CC和CMC收集器)优化性能。关键组件包括类链接器、dex2oat编译器、JIT编译器和内存管理系统。ART支持模块化更新,并通过配置文件引导优化(PGO)提升应用性能。调试能力基于JVMTI,提供断点、类重定义等功能。Android 17引入了多项改进,如分代标记-压缩GC、禁止反射修改static final字段、DEX容器格式V41等。ART架构

dengfuma的专栏 282

Hunyuan-MT-7B开源大模型应用:Pixel Language Portal在盲文翻译辅助设备中的嵌入式适配实践

本文介绍了如何在星图GPU平台上自动化部署🎮 像素语言 · 跨维传送门 (Pixel Language Portal)镜像,实现盲文翻译辅助设备的嵌入式适配。该方案基于Hunyuan-MT-7B大模型,通过优化模型压缩和交互设计,为视障群体提供高效的多语言盲文翻译服务,特别适用于教育、公共服务等场景的无障碍沟通需求。

BlackironLynx23的博客 919

madvise、fadvise、posix_madvise和posix_fadvise函数的使用

  系统调用madvise的作用:建议内核如何使用指定段的内存,可配合mmap使用。函数原型如下: #include int madvise(void *addr, size_t length, int advice);

openEuler 24.03 LTS 特性解读 | 动态复合页

长期以来 Linux 内核中物理内存是基于 struct page 来管理的,每个 page 对象描述一个基础页(如 4K),随着当前大模型、大数据等业务大内存需求,单个系统上的内存容量可以达到 TB 级别,以 page 为单位管理内存越显低效。

顺其自然~专栏 547

评价模型——层次分析法(AHP)与熵权法(EWM)

层次分析法是定性与定量结合的多准则决策、评价方法。将决策的有关元素分解成目标层、准则层和方案层,并通过人们的判断对决策方案的优劣进行排序,在此基础上进行定性和定量分析。它把人的思维过程层次化、数量化,并用数学为分析、决策、评价、预报和控制提供定量的依据。

好好学习 天天向上 2万+

论文阅读--射频电源在半导体领域的应用

射频电源(RF Power Supply)是能够输出300kHz~300GHz正弦波电压的高频交流电源,在半导体制造领域,射频电源的典型工作频率范围为400kHz∼60 MHz,主要由射频发生器(功率源)、匹配器及配套控制电路组件构成,其关键组件包括变压器与电抗器、晶闸管、绝缘栅双极型晶体管(IGBT)、钣金件、铜材及各种电子元器件。射频电源是刻蚀和薄膜沉积工艺的核心,主要用于产生等离子体,以增强气体反应活性,其性能直接影响反应腔体内等离子体的浓度、均匀性和稳定性。

伊丽莎白的学习之路 2337

Linux线程共享内存机制与虚拟地址空间管理

虚拟内存是现代操作系统的核心机制,通过地址转换和分页管理实现物理内存的高效利用。Linux采用mm_struct结构体统一管理进程地址空间,线程通过共享该结构实现零成本内存共享,这种设计在服务器编程中尤为重要。关键技术实现依赖于多级页表架构和智能的页面共享策略,包括写时复制(COW)和内存映射文件等机制。在多线程编程实践中,内存屏障和原子操作是保证数据一致性的关键,而大页内存和NUMA优化则能显著提升性能。这些原理在容器化环境中需要特别注意cgroups的资源限制特性,合理设置内存参数才能确保应用稳定运行。

weixin_33912638的博客 447

【Macbook-Latex安装部署教程】【Win-Texlive镜像下载】【简单易上手】MacTex+Vscode/Texstudio

该教程记录自己在mac()上安装部署Latex环境的经验,整个教程操作简单,配置要求少,易上手。教程分成三部分:Mactex下载与安装,Vscode插件下载与配置文件修改,Texstudio安装。

sunriseOvO的博客 2568

Pi-thon 3.14:Python底层内存优化实战指南

Python作为动态语言,其性能瓶颈长期集中在解释器启动开销、小对象缓存效率与多核NUMA架构适配性上。Pi-thon 3.14并非语法增强,而是通过编译期内存契约(TPL紧凑布局)、大页映射(MAP_HUGETLB)和环形缓冲区(circular_buffer)三大机制,重构对象生命周期管理模型。其技术价值在于将CPU缓存行对齐、TLB刷新抑制、内存碎片率控制等硬件级收益,下沉为兼容CPython ABI的零感知升级路径。典型应用场景包括嵌入式实时音频处理、边缘AI推理、高频交易微服务等对延迟与内存确定性

weixin_34239169的博客 314

命令行驱动视频剪辑:cutcli与AI自动化工作流实战

在视频内容创作领域,自动化与批量化处理是提升生产效率的关键。传统图形界面工具在应对重复性任务时往往效率低下,而通过命令行接口(CLI)驱动视频生成,则能实现流程的程序化控制。其技术原理在于将视频结构抽象为可编程的指令序列,通过解析命令生成标准化的工程文件。这种模式的核心价值在于将视频制作从手动操作转变为代码驱动,特别适合与AI编程助手集成,实现自然语言到视频草稿的自动转换。应用场景广泛覆盖社交媒体内容批量生产、教育视频自动化生成、数据可视化视频组装等领域。本文以cutcli工具为例,深入解析如何通过命令行与

weixin_42520239的博客 576

十一、学生信息管理系统(PyQt5+MySQL+PyMySQL模块实现)

学生信息管理系统(PyQt5+MySQL+PyMySQL模块实现)

ungoing的博客 8991

常见嵌入式操作系统中的内存管理机制

本文系统化梳理嵌入式操作系统中的内存管理机制。先从整体上归纳四大类常见机制——静态内存分配、动态内存堆、固定块内存池、虚拟内存与保护,并分析碎片、实时确定性、对齐、统计诊断等跨切关注点。后逐一详解 Linux、FreeRTOS、μC/OS-II、μC/OS-III、RT-Thread、Zephyr、ThreadX、NuttX、LiteOS、AliOS Things 十个主流系统的内存管理接口与实现要点,最后给出跨系统接口对比表、硬件支撑分析与选型建议,供嵌入式开发者选型与设计参考。

smallerxuan的博客 8167

华为昇腾310P3+deepseek蒸馏版性能调优:FP16精度优化全记录

本文详细介绍了在华为昇腾310P3硬件环境下优化DeepSeek蒸馏版模型FP16精度的关键技术路径。通过分层量化策略、内存分配优化和并行计算配置,显著提升模型推理性能,实现83%的并发处理能力提升,同时保持98.7%的原始模型准确率。

weixin_29074409的博客 346
上一篇: CMake 使用方法 & CMakeList.txt
下一篇: mmap msync munmap close
STN_LCD
博客等级 码龄15年 384粉丝 54原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值