kmalloc and vmalloc

详解kmalloc、vmalloc IA-32环境下的Linux对用户进程分配4G的虚拟地址空间,低3G是用户独立的空间,高1G是内核空间。用户空间的动态内存分配用malloc,而在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc。释放内存用的是kfree,vfree,或free_pages. kmalloc函数返回的是虚拟地址(线性地址). kmalloc – 内核分配内存void * 阅读详情

   在设备驱动程序中动态开辟内存,不是用malloc,而是kmalloc,或者用get_free_pages直接申请页。释放内存用的是kfree,或free_pages.

   对于提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件支持)的处理器而言,Linux提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。

  进程的4GB内存空间被人为的分为两个部分--用户空间与内核空间。用户空间地址分布从0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB为内核空间。

  内核空间中,从3G到vmalloc_start这段地址是物理内存映射区域(该区域中包含了内核镜像、物理页框表mem_map等等),比如我们使用的 VMware虚拟系统内存是160M,那么3G~3G+160M这片内存就应该映射物理内存。在物理内存映射区之后,就是vmalloc区域。对于 160M的系统而言,vmalloc_start位置应在3G+160M附近(在物理内存映射区与vmalloc_start期间还存在一个8M的gap 来防止跃界),vmalloc_end的位置接近4G(最后位置系统会保留一片128k大小的区域用于专用页面映射)

     kmalloc和get_free_page申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系,virt_to_phys()可以实现内核虚拟地址转化为物理地址:
   #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
   extern inline unsigned long virt_to_phys(volatile void * address)
   {
        return __pa(address);
   }
上面转换过程是将虚拟地址减去3G(PAGE_OFFSET=0XC000000)。

与之对应的函数为phys_to_virt(),将内核物理地址转化为虚拟地址:
   #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
   extern inline void * phys_to_virt(unsigned long address)
   {
        return __va(address);
   }
virt_to_phys()和phys_to_virt()都定义在include\asm-i386\io.h中。

-------------------------------------------------------------------------------------
1、kmalloc() 分配连续的物理地址,用于小内存分配。

2、__get_free_page() 分配连续的物理地址,用于整页分配。

  至于为什么说以上函数分配的是连续的物理地址和返回的到底是物理地址还是虚拟地址,下面的记录会做出解释。

  kmalloc() 函数本身是基于 slab 实现的。slab 是为分配小内存提供的一种高效机制。但 slab 这种分配机制又不是独立的,它本身也是在页分配器的基础上来划分更细粒度的内存供调用者使用。也就是说系统先用页分配器分配以页为最小单位的连续物理地址,然后 kmalloc() 再在这上面根据调用者的需要进行切分。

  关于以上论述,我们可以查看 kmalloc() 的实现,kmalloc()函数的实现是在 __do_kmalloc() 中,可以看到在 __do_kmalloc()代码里最终调用了 __cache_alloc() 来分配一个 slab,其实kmem_cache_alloc() 等函数的实现也是调用了这个函数来分配新的 slab。我们按照 __cache_alloc()函数的调用路径一直跟踪下去会发现在 cache_grow() 函数中使用了 kmem_getpages()函数来分配一个物理页面,kmem_getpages() 函数中调用的alloc_pages_node() 最终是使用 __alloc_pages() 来返回一个struct page 结构,而这个结构正是系统用来描述物理页面的。这样也就证实了上面所说的,slab 是在物理页面基础上实现的。kmalloc() 分配的是物理地址。

  __get_free_page() 是页面分配器提供给调用者的最底层的内存分配函数。它分配连续的物理内存。__get_free_page() 函数本身是基于 buddy 实现的。在使用 buddy 实现的物理内存管理中最小分配粒度是以页为单位的。关于以上论述,我们可以查看__get_free_page()的实现,可以看到__get_free_page()函数只是一个非常简单的封状,它的整个函数实现就是无条件的调用 __alloc_pages() 函数来分配物理内存,上面记录 kmalloc()实现时也提到过是在调用 __alloc_pages() 函数来分配物理页面的前提下进行的 slab 管理。那么这个函数是如何分配到物理页面又是在什么区域中进行分配的?回答这个问题只能看下相关的实现。可以看到在 __alloc_pages() 函数中,多次尝试调用get_page_from_freelist() 函数从 zonelist 中取得相关 zone,并从其中返回一个可用的 struct page 页面(这里的有些调用分支是因为标志不同)。至此,可以知道一个物理页面的分配是从 zonelist(一个 zone 的结构数组)中的 zone 返回的。那么 zonelist/zone 是如何与物理页面关联,又是如何初始化的呢?继续来看 free_area_init_nodes() 函数,此函数在系统初始化时由 zone_sizes_init() 函数间接调用的,zone_sizes_init()函数填充了三个区域:ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。并把他们作为参数调用 free_area_init_nodes(),在这个函数中会分配一个 pglist_data 结构,此结构中包含了 zonelist/zone结构和一个 struct page 的物理页结构,在函数最后用此结构作为参数调用了 free_area_init_node() 函数,在这个函数中首先使用 calculate_node_totalpages() 函数标记 pglist_data 相关区域,然后调用 alloc_node_mem_map() 函数初始化 pglist_data结构中的 struct page 物理页。最后使用 free_area_init_core()函数关联 pglist_data 与 zonelist。现在通以上分析已经明确了__get_free_page() 函数分配物理内存的流程。但这里又引出了几个新问题,那就是此函数分配的物理页面是如何映射的?映射到了什么位置?到这里不得不去看下与 VMM 相关的引导代码。

  在看 VMM 相关的引导代码前,先来看一下 virt_to_phys() 与phys_to_virt 这两个函数。顾名思义,即是虚拟地址到物理地址和物理地址到虚拟地址的转换。函数实现十分简单,前者调用了__pa( address ) 转换虚拟地址到物理地址,后者调用 __va(addrress ) 将物理地址转换为虚拟地址。再看下 __pa __va 这两个宏到底做了什么。

  #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
  #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))

  通过上面可以看到仅仅是把地址加上或减去 PAGE_OFFSET,而PAGE_OFFSET 在 x86 下定义为 0xC0000000。这里又引出了疑问,在 linux 下写过 driver 的人都知道,在使用 kmalloc() 与

  __get_free_page() 分配完物理地址后,如果想得到正确的物理地址需要使用 virt_to_phys() 进行转换。那么为什么要有这一步呢?我们不分配的不就是物理地址么?怎么分配完成还需要转换?如果返回的是虚拟地址,那么根据如上对 virt_to_phys() 的分析,为什么仅仅对 PAGE_OFFSET 操作就能实现地址转换呢?虚拟地址与物理地址之间的转换不需要查页表么?代着以上诸多疑问来看 VMM 相关的引导代码。

  直接从 start_kernel() 内核引导部分来查找 VMM 相关内容。可以看到第一个应该关注的函数是 setup_arch(),在这个函数当中使用paging_init() 函数来初始化和映射硬件页表(在初始化前已有 8M内存被映射,在这里不做记录),而 paging_init() 则是调用的pagetable_init() 来完成内核物理地址的映射以及相关内存的初始化。在 pagetable_init() 函数中,首先是一些 PAE/PSE/PGE 相关判断与设置,然后使用 kernel_physical_mapping_init() 函数来实现内核物理内存的映射。在这个函数中可以很清楚的看到,pgd_idx 是以PAGE_OFFSET 为启始地址进行映射的,也就是说循环初始化所有物理地址是以 PAGE_OFFSET 为起点的。继续观察我们可以看到在 PMD 被初始化后,所有地址计算均是以 PAGE_OFFSET 作为标记来递增的。分析到这里已经很明显的可以看出,物理地址被映射到以 PAGE_OFFSET 开始的虚拟地址空间。这样以上所有疑问就都有了答案。kmalloc() 与__get_free_page() 所分配的物理页面被映射到了 PAGE_OFFSET 开始的虚拟地址,也就是说实际物理地址与虚拟地址有一组一一对应的关系,

  正是因为有了这种映射关系,对内核以 PAGE_OFFSET 启始的虚拟地址的分配也就是对物理地址的分配(当然这有一定的范围,应该在 PAGE_OFFSET与 VMALLOC_START 之间,后者为 vmalloc() 函数分配内存的启始地址)。这也就解释了为什么 virt_to_phys() 与 phys_to_virt() 函数的实现仅仅是加/减 PAGE_OFFSET 即可在虚拟地址与物理地址之间转换,正是因为了有了这种映射,且固定不变,所以才不用去查页表进行转换。这也同样回答了开始的问题,即 kmalloc() / __get_free_page() 分配的是物理地址,而返回的则是虚拟地址(虽然这听上去有些别扭)。正是因为有了这种映射关系,所以需要将它们的返回地址减去 PAGE_OFFSET 才可以得到真正的物理地址。


       进程的4GB内存空间被人为的分为两个部分--用户空间与内核空间。用户空间地址分布从0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB为内核空间。

内核空间中,从3G到vmalloc_start这段地址是物理内存映射区域(该区域中包含了内核镜像、物理页框表mem_map等等),比如我们使用 的 VMware虚拟系统内存是160M,那么3G~3G+160M这片内存就应该映射物理内存。在物理内存映射区之后,就是vmalloc区域。对于 160M的系统而言,vmalloc_start位置应在3G+160M附近(在物理内存映射区与vmalloc_start期间还存在一个8M的gap 来防止跃界),vmalloc_end的位置接近4G(最后位置系统会保留一片128k大小的区域用于专用页面映射)

kmalloc和get_free_page申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系,virt_to_phys()可以实现内核虚拟地址转化为物理地址:
   #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
   extern inline unsigned long virt_to_phys(volatile void * address)
   {
        return __pa(address);
   }
上面转换过程是将虚拟地址减去3G(PAGE_OFFSET=0XC000000)。

与之对应的函数为phys_to_virt(),将内核物理地址转化为虚拟地址:
   #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
   extern inline void * phys_to_virt(unsigned long address)
   {
        return __va(address);
   }
virt_to_phys()和phys_to_virt()都定义在include\asm-i386\io.h中。

而vmalloc申请的内存则位于vmalloc_start~vmalloc_end之间,与物理地址没有简单的转换关系,虽然在逻辑上它们也是连续的,但是在物理上它们不要求连续。


kmalloc和vmalloc的区别 kmalloc和vmalloc完全不同。 kmalloc kmalloc申请一段物理地址和逻辑地址连续的内存空间。 /* 申请一段物理地址连续的内存空间 */ static __always_inline void *kmalloc(size_t size, gfp_t flags) { if (__builtin_constant_p(size)) { if (size > KMA... 阅读详情

相关推荐

DEM边界数值爆炸?用ArcGIS空间分析工具链搞定异常值过滤全流程

本文针对DEM数据处理中常见的边界数值爆炸问题,提供了一套完整的ArcGIS空间分析解决方案。文章深入剖析了异常值产生的根源,并详细介绍了从诊断、定位到使用栅格计算器、重分类等工具进行精准过滤与修复的全流程工作流,帮助用户彻底解决由插值误差、数据拼接及坐标系转换引发的数值异常。

weixin_29269441的博客 148

linux中kmalloc和vmalloc的使用

kmalloc和get_free_page申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系,virt_to_phys()可以实现内核虚拟地址转化为物理地址: #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) extern inline unsigned long v...

互联网 609

问题解决:打开VMware创建的虚拟机,电脑立刻蓝屏并重启

VMware Workstation 与 Device/Credential Guard 不兼容。在禁用 Device/Credenti

weixin_55118477的博客 3万+

vmalloc 和 kmalloc 的详解

琢磨了很久也参考了很多资料,发现很多都说的有点含糊,在这里先介绍一下Linux中对实际内存的一个分配,Linux内核将实际内存(注意是实际内存,这里暂且考虑不大于1G的内存)分为三个区段:可用于DMA的内存、常规内存以及高端内存。这里只介绍一下高端内存与地段内存。

su_linux的专栏 1243

深入解析Lora SX1268:从基础配置到高级应用

本文深入解析了LoRa SX1268芯片从基础配置到高级应用的全过程。详细介绍了LoRa与FSK模式选择、核心参数(BW、SF、CR、LDRO)的配置策略、数据帧结构、缓冲区管理以及CAD模式等关键概念,旨在帮助开发者充分发挥SX1268在远距离、低功耗物联网通信中的潜力,并提供实用的调试技巧。

weixin_29168393的博客 119

NI-HIL学习开篇

自我介绍下,四年零部件厂工作经验,一年(至今)主机厂工作经验,负责BMS/VCU方向软硬件测试。 学习目的:把握新能源汽车的测试发展趋势,顺应历史的洪流。 学习目标:1.掌握HIL开发测试流程中的IO配置、开环验证、闭环模型开发及调试、自动化测试 2.掌握第三方模型的搭建及simulink关联仿真(2019.05.21新增:需巩固练习matlab基础——2...

masonson的专栏 4177

kmalloc vmalloc 区别

在设备驱动程序中动态开辟内存,不是用malloc,而是kmalloc,或者用get_free_pages直接申请页。释放内存用的是kfree,或free_pages.    对于提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件支持)的处理器而言,Linux提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。   进程的4GB内存空间被人为的分为两个部分--用户

YOURSUPERHERO的专栏 1802

关于使用EB tresos出现无法激活的情况解决

我在安装eb studio时就是在激活方面有问题导致无法使用,下面讲解出现了什么问题以及我如何去解除的。EB安装完成时需要激活才能使用的,不然都打开或者建立不了工程,一直都是报的dns服务器错误,好的,那我改dns服务器地址。填写dns服务器地址,也可以换成别的,自己百度一下适合自己的。这是解决方案哈哈哈哈。

weixin_43673603的博客 6182

Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别[转]

转自:https://www.cnblogs.com/sky-heaven/p/7390370.html我们都知道在用户空间动态申请内存用的函数是 malloc(),这个函数在各种操作系统上的使用是一致的,对应的用户空间内存释放函数是 free()。注意:动态申请的内存使用完后必须要释放,否则会造成内存泄漏,如果内存泄漏发生在内核空间,则会造成系统崩溃。   那么,在内核空间中如何申请内存呢?一般...

wangwei8126的博客 801

基于STM32+华为云设计的智慧农业灌溉系统(2023升级版)(158)

本项目设计一种基于STM32的智慧农业监测系统。该系统能够检测空气温度、湿度、光强度和土壤湿度等关键指标,并自动调节浇水量,实现作物生长环境的精细化管理。同时,本项目还支持本地LCD屏幕数据显示和通过ESP8266上传数据到华为云物联网平台,同时搭建流媒体服务器实现摄像头远程监控。最重要的是,本项目将利用Qt开发Android手机APP,使用户可以远程查看监测情况,了解农作物生成情况。

1万+

GPS天线结构、原理、测试

【有源陶瓷天线构成】GPS天线是由接收天线和前置放大器两个部件组成。GPS接收天线的作用,是将卫星来的无线电信号的电磁波能量变换成接收机电子器件可摄取应用的电流。绝大部分内置GPS天线为右旋极化陶瓷介质,其组成部分为:陶瓷天线、低噪音信号模块、线缆、[接头](h

数字世界 万物互联 2万+

kmalloc vmalloc malloc区别

kmalloc()和vmalloc()介绍 kmalloc() 用于申请较小的、连续的物理内存 1. 以字节为单位进行分配,在中 2. void *kmalloc(size_t size, int flags)分配的内存物理地址上连续,虚拟地址上自然连续 3. gfp_mask标志:什么时候使用哪种标志?如下: ———————————————————————————————- 情形

深海蓝的技术随笔 868

RK3588,V4l2 读取Gmsl相机, Rga yuv422转换rgb (dma), 实现零拷贝

RK3588, 使用V4l2 读取 gmsl 相机,获得yuv422格式图像, 使用 rga 转换 rgb 图像。减少cpu占用率. 内存管理方式采用 dma,实现零拷贝.

J。 1262

malloc、calloc、kmalloc、vmalloc 详解

本文详细解析了用户空间和内核空间的四种内存分配函数:malloc、calloc、kmalloc和vmalloc。在用户空间,malloc通过brk或mmap系统调用分配内存,calloc自动初始化内存为零,realloc可调整内存大小。内核空间中,kmalloc分配物理连续内存,适合DMA操作;vmalloc分配虚拟连续但物理分散的内存,适合大块分配。文章通过内存布局图、对比表格和代码示例,展示了各函数的使用场景和内部机制,为开发者提供了内存分配的最佳实践指导。

道阻其长,未来可期。笔耕不辍,行则将至! 1480

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

kmalloc、vmalloc、malloc的区别

<br />简单的说:kmalloc和vmalloc是分配的是内核的内存,malloc分配的是用户的内存 kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc不保证任何东西(这点是自己猜测的,不一定正确)kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相对较大 内存只有在要被DMA访问的时候才需要物理上连续 vmalloc比kmalloc要慢<br /> <br />详细的解释:<br />      对于提供了MMU(存储管理器,

Macross的专栏 8万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

关于kmalloc、vmalloc及kmap

 1、  kmalloc()是内核中最常见的内存分配方式,它最终调用伙伴系统的__get_free_pages()函数分配,根据传递给这个函数的flags参数,决定这个函数的分配适合什么场合,如果标志是GFP_KERNEL则仅仅可以用于进程上下文中,如果标志GFP_ATOMIC则可以用于中断上下文或者持有锁的代码段中。kmalloc返回的线形地址是直接映射的,而且用连续物理页满足分配请求,

gxfan的专栏 2万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Linux内核内存分配函数kmalloc、kzalloc和vmalloc

内核内存分配函数kmalloc/kzalloc/vmalloc的对比和示例程序

weixin_40313940的博客 3454

kmalloc vmalloc malloc mmap

参考:http://blog.youkuaiyun.com/tigerjb/article/details/6412881 http://linux.chinaunix.net/techdoc/system/2008/06/16/1011365.shtml http://www.xiangmocheng.com/2009/09/kmalloc-vmalloc-malloc-difference/

SunnyBeiKe的专栏 2623

Linux驱动编程 - kmalloc、vmalloc区别

Linux内核中kmalloc、vmalloc区别和使用笔记

hinewcc的博客 1485

linux内核kmalloc与vmalloc的区别.

一.kmalloc(): 用于申请较小的、连续的物理内存. 1. 以字节为单位进行分配,在中 2. void *kmalloc(size_t size, int flags):分配的内存物理地址上连续,虚拟地址上自然连续 3. void kfree(const void *ptr):释放由kmalloc()分配出来的内存块 二.vmalloc(): 用于申请较大的内存空间,虚拟

xqzhan的专栏 3701

Kmalloc Vmalloc 与malloc 的区别

总的来说 kmalloc和vmalloc是分配内核的内存,malloc分配的是用户空间的内存。 kmalloc 保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc申请的内存不一定连续(用户空间存储以空间链表的方式组织(地址递增),每一个链表块包含一个长度、一个指向下一个链表块的指针以及一个指向自身的存储空间指针。) kmalloc能分配的大小有限,vmalloc与malloc能分配的空间大小相对较大。 内存只有在要被DMA访问的时候才需要物理上连续。 vma

weixin_42005898的博客 3175

kmalloc,vmalloc,malloc,mmap

无

qq_42693685的博客 809

傻傻分不清楚 kmalloc、vmalloc和malloc之间有什么区别以及实现上的差异

kmalloc、vmalloc 和 malloc 的区别及实现差异详解这三者都是内存分配函数,但适用于不同场景(内核空间或用户空间),在内存连续性、实现机制和适用场景上有显著差异。

sinat_37817094的博客 1338

Linux内存管理:(三)kmalloc、vmalloc、malloc、mmap

文章说明:Linux内核版本:5.0架构:ARM64参考资料及图片来源:《奔跑吧Linux内核》

qq_58538265的博客 3756

深入解析 kmalloc、vmalloc 和 malloc

特性mallockmallocvmalloc使用空间用户空间内核空间内核空间连续性虚拟地址连续虚拟+物理地址连续虚拟地址连续、物理不一定连续速度快很快相对较慢大小适用范围小到大小(<128KB)大(MB甚至更多)释放函数freekfreevfree应用场景应用程序开发驱动开发/小内存块驱动开发/大内存块。

m0_53518956的博客 1279
上一篇: IGMP技术总结(2)
下一篇: UPnP协议学习
kernel_learner
博客等级 码龄15年 60粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值