Linux内核中常见内存分配函数

2023-05-16

1.      原理说明

Linux内核中采 用了一种同时适用于32位和64位系统的内 存分页模型,对于32位系统来说,两级页表足够用了,而在x86_64系 统中,用到了四级页表,如图2-1所示。四级页表分别为:

l         页全局目录(Page Global Directory)

l         页上级目录(Page Upper Directory)

l         页中间目录(Page Middle Directory)

l         页表(Page Table)

    页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址,每一个页表项指 向一个页框。Linux中采用4KB大小的 页框作为标准的内存分配单元。

 

多级分页目录结构

1.1.      伙伴系统算法

    在实际应用中,经常需要分配一组连续的页框,而频繁地申请和释放不同大小的连续页框,必然导致在已分配页框的内存块中分散了许多小块的 空闲页框。这样,即使这些页框是空闲的,其他需要分配连续页框的应用也很难得到满足。

    为了避免出现这种情况,Linux内核中引入了伙伴系统算法(buddy system)。把所有的空闲页框分组为11个 块链表,每个块链表分别包含大小为12481632641282565121024个连续页框的页框块。最大可以申请1024个连 续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。

    假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块,如果没有,就去512个 页框的链表中找,找到了则将页框块分为2256个 页框的块,一个分配给应用,另外一个移到256个页框的链表中。如果512个页框的链表中仍没有空闲块,继续向1024个页 框的链表查找,如果仍然没有,则返回错误。

    页框块在释放时,会主动将两个连续的页框块合并为一个较大的页框块。

1.2.      slab分 配器

    slab分配器源于 Solaris 2.4 的 分配算法,工作于物理内存页框分配器之上,管理特定大小对象的缓存,进行快速而高效的内存分配。

    slab分配器为每种使用的内核对象建立单独的缓冲区。Linux 内核已经采用了伙伴系统管理物理内存页框,因此 slab分配器直接工作于伙伴系 统之上。每种缓冲区由多个 slab组成,每个 slab就是一组连续的物理内存页框,被划分成了固定数目的对象。根据对象大小的不同,缺省情况下一个 slab 最多可以由 1024个页框构成。出于对齐 等其它方面的要求,slab 中分配给对象的内存可能大于用户要求的对象实际大小,这会造成一定的 内存浪费。

2.      常用内存分配函数

2.1.      __get_free_pages

    unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)

 

    __get_free_pages函数是最原始的内存分配方式,直接从伙伴系统中获取原始页框,返回值为第一个页框的起始地址。__get_free_pages在实现上只是封装了alloc_pages函 数,从代码分析,alloc_pages函数会分配长度为1<<order的 连续页框块。order参数的最大值由include/linux/Mmzone.h文 件中的MAX_ORDER宏决定,在默认的2.6.18内 核版本中,该宏定义为10。也就是说在理论上__get_free_pages函 数一次最多能申请1<<10 * 4KB也就是4MB的 连续物理内存。但是在实际应用中,很可能因为不存在这么大量的连续空闲页框而导致分配失败。在测试中,order10时分配成功,order11则返回错误。

2.2.      kmem_cache_alloc

    struct kmem_cache *kmem_cache_create(const char *name, size_t size,

        size_t align, unsigned long flags,

        void (*ctor)(void*, struct kmem_cache *, unsigned long),

        void (*dtor)(void*, struct kmem_cache *, unsigned long))

    void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags)

 

    kmem_cache_create/ kmem_cache_alloc是基于slab分配器的一种内存分配方式,适用于反复分配释放同一大小内存块的场合。首先用kmem_cache_create创建一个高速缓存区域,然后用kmem_cache_alloc从 该高速缓存区域中获取新的内存块。 kmem_cache_alloc一次能分配的最大内存由mm/slab.c文件中的MAX_OBJ_ORDER宏 定义,在默认的2.6.18内核版本中,该宏定义为5, 于是一次最多能申请1<<5 * 4KB也就是128KB的 连续物理内存。分析内核源码发现,kmem_cache_create函数的size参数大于128KB时会调用BUG()。测试结果验证了分析结果,用kmem_cache_create分 配超过128KB的内存时使内核崩溃。

2.3.      kmalloc

    void *kmalloc(size_t size, gfp_t flags)

 

    kmalloc是内核中最常用的一种内存分配方式,它通过调用kmem_cache_alloc函 数来实现。kmalloc一次最多能申请的内存大小由include/linux/Kmalloc_size.h的 内容来决定,在默认的2.6.18内核版本中,kmalloc一 次最多能申请大小为131702B也就是128KB字 节的连续物理内存。测试结果表明,如果试图用kmalloc函数分配大于128KB的内存,编译不能通过。

2.4.      vmalloc

    void *vmalloc(unsigned long size)

 

    前面几种内存分配方式都是物理连续的,能保证较低的平均访问时间。但是在某些场合中,对内存区的请求不是很频繁,较高的内存访问时间也 可以接受,这是就可以分配一段线性连续,物理不连续的地址,带来的好处是一次可以分配较大块的内存。图3-1表 示的是vmalloc分配的内存使用的地址范围。vmalloc对 一次能分配的内存大小没有明确限制。出于性能考虑,应谨慎使用vmalloc函数。在测试过程中, 最大能一次分配1GB的空间。

 

Linux内核部分内存分布

2.5.      dma_alloc_coherent

    void *dma_alloc_coherent(struct device *dev, size_t size,

ma_addr_t *dma_handle, gfp_t gfp)

    DMA是一种硬件机制,允许外围设备和主存之间直接传输IO数据,而不需要CPU的参与,使用DMA机制能大幅提高与设备通信的 吞吐量。DMA操作中,涉及到CPU高速缓 存和对应的内存数据一致性的问题,必须保证两者的数据一致,在x86_64体系结构中,硬件已经很 好的解决了这个问题, dma_alloc_coherent__get_free_pages函数实现差别不大,前者实际是调用__alloc_pages函 数来分配内存,因此一次分配内存的大小限制和后者一样。__get_free_pages分配的内 存同样可以用于DMA操作。测试结果证明,dma_alloc_coherent函 数一次能分配的最大内存也为4M

2.6.      ioremap

    void * ioremap (unsigned long offset, unsigned long size)

    ioremap是一种更直接的内存“分配”方式,使用时直接指定物理起始地址和需要分配内存的大小,然后将该段 物理地址映射到内核地址空间。ioremap用到的物理地址空间都是事先确定的,和上面的几种内存 分配方式并不太一样,并不是分配一段新的物理内存。ioremap多用于设备驱动,可以让CPU直接访问外部设备的IO空间。ioremap能映射的内存由原有的物理内存空间决定,所以没有进行测试。

2.7.      Boot Memory

    如果要分配大量的连续物理内存,上述的分配函数都不能满足,就只能用比较特殊的方式,在Linux内 核引导阶段来预留部分内存。

2.7.1.       在内核引导时分配内存

    void* alloc_bootmem(unsigned long size)

    可以在Linux内核引导过程中绕过伙伴系统来分配大块内存。使用方法是在Linux内核引导时,调用mem_init函数之前 用alloc_bootmem函数申请指定大小的内存。如果需要在其他地方调用这块内存,可以将alloc_bootmem返回的内存首地址通过EXPORT_SYMBOL导 出,然后就可以使用这块内存了。这种内存分配方式的缺点是,申请内存的代码必须在链接到内核中的代码里才能使用,因此必须重新编译内核,而且内存管理系统 看不到这部分内存,需要用户自行管理。测试结果表明,重新编译内核后重启,能够访问引导时分配的内存块。

2.7.2.       通过内核引导参数预留顶部内存

    Linux内核引导时,传入参数“memsize”保留顶部的内存区间。比如系统有256MB内 存,参数“mem248M”会预留顶部的8MB内存,进入系统后可以调用ioremap(0xF8000000x800000)来申请这段内存。

3.      几种分配函数的比较

 

 

分配原理

最大内存

其他

__get_free_pages

直接对页框进行操作

4MB

适用于分配较大量的连续物理内存

kmem_cache_alloc

基于slab机制实现

128KB

适合需要频繁申请释放相同大小内存块时使用

kmalloc

基于kmem_cache_alloc实现

128KB

最常见的分配方式,需要小于页框大小的内存时可以使用

vmalloc

建立非连续物理内存到虚拟地址的映射

 

物理不连续,适合需要大内存,但是对地址连续性没有要求的场合

dma_alloc_coherent

基于__alloc_pages实现

4MB

适用于DMA操 作

ioremap

实现已知物理地址到虚拟地址的映射

 

适用于物理地址已知的场合,如设备驱动

alloc_bootmem

在启动kernel时,预留一段内存,内核看不见

 

小于物理内存大小,内存管理要求较高

 

   注:表中提到的最大内存数据来自CentOS5.3 x86_64系统,其他系统和体系结构会有不同

 

原文地址 http://blog.csdn.net/wzhwho/archive/2009/12/13/4996510.aspx

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux内核中常见内存分配函数 的相关文章

  • 基于ROS机器人的3D物体识别与三维重建(一) 介绍篇

    基于ROS机器人的3D物体识别与三维重建 一 xff09 介绍篇 由来 xff1a 清理电脑硬盘 xff0c 发现了当时做毕设的一些资料 xff0c 所以打算整理一下资料和代码写成专栏 xff0c 记录下当时的暗金岁月 xff0c 尽管现在
  • WIFI模块实现网络连接

    WiFi模块连接 xff0c 通过串口调试助手来配置 STA 43 连接TCP Server 1 AT 43 CWMODE DEF 61 1 工作在单station模组 xff0c 设置参数保存到flash 2 AT 43 CWJAP DE
  • 关于飞机绕地球飞行一圈的加油问题

    已知 xff1a 每个飞机只有一个油箱 xff0c 飞机之间可以相互加油 xff0c 注意是相互 xff0c 没有加油机 xff0c 一箱油可供一架飞机绕地球飞半圈 问题 xff1a 为使至少一架飞机绕地球一圈回到起飞时的飞机场 xff0c
  • 【C/C++/QT/ 移植/导入Mavlink V2.0/Mavlink V1.0教程】

    提示 xff1a 本文针对的实例是Mavlink V2 0版本 xff0c Mavlink V1 0版本其实也是类似的的步骤 xff0c 选择的mavlink库不一样而已 官方链接放在此 xff1a Install MAVLink MAVL
  • 无需修改bios即可让任意主板实现NVME启动

    使用Clover四叶草引导加载NVMe驱动 除了对BIOS的硬改之外 xff0c 还有一种更安全的软件方案 xff1a 使用Clover四叶草引导加载NVMe驱动 Clover是著名的黑苹果引导软件 xff0c 这里借用它来实现对预引导 x
  • 如何将PX4 User Guide导出为PDF

    PX4 Autopilot User Guide PDF导出 如何将PX4 User Guide导出为PDF1 工具安装安装nodejs安装ebook conver安装svgexport安装gitbook 2 输出PX4 Guide文档下载
  • CentOS7 yum安装docker失败的看过来

    背景 在百度上搜到一些前辈关于安装docker教程 xff0c 例如 xff1a 点击打开链接 但都报出找不到源的信息 xff0c 估计导致该情况往往是国内使用外国源被和谐的原因吧 解决 1 使用阿里云的yum源 cd etc yum re
  • 持续交付(CD)与持续集成(CI)

    测试基础设施是指支持自动化测试运行 测试开发 测试管理以及与研发环境集成的综合性平台 敏捷测试离不开稳定 高效 准确的基础设施 xff0c 以满足对于持续测试 持续反馈的需要 xff1b 同时 xff0c 持续集成 持续交付和 DevOps
  • 树莓派c语言串口通讯程序

    在网上搜了很多关于树莓派串口通讯的例子 xff0c 但是都是用python写的 xff0c 虽然python很有名 xff0c 而且最近也在学习这门语言 xff0c 但是还是想用c语言实现一下 xff0c 因为需要用到整套系统里 xff0c
  • 怎么阅读论文,写心得体会

    收集资料 xff1a 阅读学术论文的心得体会 xff01 如何阅读学术论文 和上一篇类似大牛写论文的心得几年的写论文和审稿心得 文献阅读心得体会格式 xff1a 1 看论文题目 xff0c 做出论文类别判别 新理论 新方法 解决新问题 最高
  • 了解什么是枚举(enumeration)

    1 枚举是一组常量的集合 还可以看成包含有限特定的对象 2 自定义枚举的步骤 xff1a 将构造器私有化private将get方法拿掉在类的内部直接创建固定的对象 xff0c 比如 xff1a public static Season SP
  • python学习三十八-九天(python程序中进程的操作)

    主要内容 python的multiprocess模块和用法 在python程序中的进程操作 之前我们已经了解了很多进程相关的理论知识 xff0c 了解进程是什么应该不再困难了 xff0c 刚刚我们已经了解了 xff0c 运行中的程序就是一个
  • 电脑开机安装流氓软件、弹广告处理办法

    今天处理了一台开机自动安装流氓软件的电脑 xff0c 而且还弹广告 现在写下处理过程 文章目录 一 卸载软件 xff08 1 xff09 控制面板卸载 xff08 2 xff09 安装路径卸载 二 禁用任务计划程序三 删除软件安装包四 修改
  • VScode中使用git进行版本控制

    VScode中使用git进行版本控制 一 安装与配置二 初始化和提交本地仓库三 提交到远程仓库四 克隆和拉取1 克隆2 拉取 五 修改后的提交六 免密提交七 其他命令1 撤销2 Git 分支命令3 暂时保存更改4 同时提交多个仓库 一 安装
  • SLAM的前世今生 终于有人说清楚了

    SLAM的前世今生 终于有人说清楚了 硬创公开课 from xff1a http www leiphone com news 201605 5etiwlnkWnx7x0zb html 2016 05 16 19 40 宗仁 0 条评论 今年
  • 使用catkin进行工程管理

    catkin是什么 这是一个管理ros代码的工程管理工具 xff0c 基于cmake xff0c 但是比cmake多更多功能 xff0c 是cmake上层的代码管理规则 ros之前采用的是ros build xff0c 现在用catkin
  • ROS-melodic 安装 及:rosdep init 和 rosdep update 失败问题解决总结

    正常安装ros流程 ros 安装 melodic sudo sh c 39 etc lsb release amp amp echo 34 deb http mirrors tuna tsinghua edu cn ros ubuntu D
  • ubuntu 安装Opencv4版本后安装Opencv3,并在项目中区分使用

    安装 xff1a ubuntu 安装OpenCV3版本后安装OpenCV4 xff0c 且多版本共存 wyyang2的博客 CSDN博客 https blog csdn net wyyang2 article details 1039894
  • Ubuntu 16.04录屏软件

    Ubuntu 16 04安装录屏软件Simple Screen Recorder https www maartenbaert be simplescreenrecorder https jingyan baidu com article
  • debug时一个非常坑爹的问题——单步调试正常但是运行没结果

    单步调试能得到正确答案 xff0c 运行不出来 本人用的是codeblocks xff0c 20 03版本 话说有一天晚上 xff0c 那个不平凡的夜 xff0c 还有不到十个小时数据结构的实验课就要上交报告了 xff0c 而自己的程序却出

随机推荐

  • DataX使用、同步MySQL数据到HDFS案例

    文章目录 4 DataX使用4 1 DataX使用概述4 1 1 DataX任务提交命令4 1 2 DataX配置文件格式 4 2 同步MySQL数据到HDFS案例4 2 1 MySQLReader之TableMode4 2 1 1 编写配
  • 支持期限提至10年,Ubuntu 18.04 LTS

    给技术最前线加星标 xff0c 每天看技术热点 综合自 xff1a cnBeta COM Solidot Mark Shuttleworth宣布将支持Ubuntu 18 04 LTS长达十年时间 xff0c 让LTS版本的含金量更足 xff
  • 实训第五天:我的页面布局,API接口(一言,天气预报)

    1 不用不用脚本和弹窗获取手机信息 xff0c 用微信公众平台的组件开发能力 open data用于展示微信开放的数据 部分代码 xff1a lt view class 61 34 container 34 gt lt view class
  • 这是一个失败的程序员

    写程序至今 xff0c 未入门 xff0c 什么都不懂 xff01
  • adb dumpsys命令用法

    dumpsys命令功能很强大 xff0c 能dump系统服务的各种状态 xff0c 非常有必要熟悉该命令的用法以及含义 一 概述 1 1 dumpsys命令用法 可通过dumpsys命令查询系统服务的运行状态 对象的成员变量属性值 xff0
  • matlab subs函数

    在matlab命令行查看subs函数的帮助 subs函数一共有三种使用方法 xff1a subs s old new subs s new subs s 点击 subs 的参考页可以看到下面的详细说明 第一种使用方法 说明 xff1a su
  • Docker----如何更改docker镜像的存储路径

    原文链接 Docker 如何更改docker镜像的存储路径 背景 随着docker容器已经镜像的使用 xff0c docker镜像占用大量磁盘空间 xff0c 当然可以通过不断的删除镜像或者设置定时任务删除镜像 xff0c 但是有时候还是挺
  • ROS的geometry_msgs/PoseWithCovarianceStamped Message 消息格式

    溪西创客小屋 geometry msgs PoseWithCovarianceStamped Message Raw Message Definition This expresses an estimated pose with a re
  • 线程和进程的理解

    一 介绍线程和进程 什么是线程 是程序执行的最小单位 xff0c 一个进程在执行过程中产生建多个线程 xff0c 同一进程中的 多个 线程共享同一块内存空间及系统资源 xff0c 线程数进程的一部分 xff0c 因此线程数也被称为轻量级进程
  • Windows安装tensorflow-gpu

    0 想在Windows环境安装tensorflow gpu xff0c 显卡必须是N卡 xff08 本文以3070显卡为例进行说明 xff09 1 安装好Anaconda以及Pycharm xff08 安装教程 xff1a https ww
  • 16.进程-进程间通信概述

    进程间通信 xff0c 也就是大家常说的 IPC Inter Process Communication xff0c 指的是不同的进程间进行交流 xff0c 本质上就是进程之间发送和接收数据 xff1b 本质上 xff0c 信号也是属于进程
  • PNP问题-位姿估计方法梳理(pose estimation)

    tags 单目视觉 位姿测量 目标3D精确模型已知 xff08 建立2D 3D对应关系 xff09 xff1a 点特征 P3P问题 基于针孔成像模型 Gao的方法 xff08 opencv emgucv xff09 Kneip 的 P3P
  • 室内无人机定位导航

    个人观点 xff1a 可研究的方向 1 静态规划方面 xff1a 将控制与定位结合起来 xff1b 修正回环检测误差 xff0c 提高算法的计算精度和执行效率 xff1b 2 动态规划方面 xff1a 用神经网络识别运动物体的行进方向 xf
  • 树莓派3b程序控制无人机 (一)——电脑连树莓派

    设备 xff1a 树莓派3b xff08 备有键盘 xff0c 鼠标 xff09 xff1b win10 x64笔记本 xff1b UAV pixhawk飞控板 etc network interfaces 的设置可参考以下链接 xff1a
  • 三星6410裸机程序开发

    网上关于S3C6410裸机程序开发都是基于RealView RVDS 也有一些是基于eclipse的 xff0c 但都没有详细介绍在eclipse中如何建立S3C6410裸机程序工程 尽管友善之臂提供的6410裸机程序示例使用了eclips
  • linux socket can程序cantool

    最近写了个自认为不错的基于linux socket can程序 xff0c 主要功能 xff1a 程序具备全部CAN功能 xff0c 包括CAN标准帧 扩展帧接收与发送 CAN总线错误判断 环回等功能适用基于LINUX SOCKET机制实现
  • Linux CAN编程详解

    Linux CAN编程详解 是一篇百度文库上的文档 xff0c 主要描述了以下内容 xff1a can总线介绍及其帧类型 xff1b Linux 系统中CAN 接口配置 xff1b Linux 系统中CAN 接口应用程序开发 xff1b L
  • c++中冒号(:)和双冒号(::)的用法和c/c++ 位域结构体

    1 冒号 xff08 xff09 用法 xff08 1 xff09 表示结构体内 位域的定义 xff08 即该变量占几个bit空间 xff09 typedef struct XXX unsigned char a 4 unsigned ch
  • CAN总线与RS485的比较

    最近一个项目总体方案设计为分布式系统 xff0c 于是在通讯上纠结于CAN总线还是RS485 因此在网上搜索一些了一些关于RS485和CAN总线的资料 xff0c 除进一步认识RS485通讯特点外 xff0c 认识了CAN总线的特点及其与R
  • Linux内核中常见内存分配函数

    1 原理说明 Linux 内核中采 用了一种同时适用于32 位和64 位系统的内 存分页模型 xff0c 对于32 位系统来说 xff0c 两级页表足够用了 xff0c 而在x86 64 系 统中 xff0c 用到了四级页表 xff0c 如