首页 > 系统相关 >内核态内存的正确使用方法

内核态内存的正确使用方法

时间:2023-10-08 16:37:38浏览次数:41  
标签:正确 映射 虚拟地址 内核 kmap vmalloc 内存

前言

看完了伙伴系统的设计、slab分配器的设计、vmalloc、kmalloc这些内容对于内存管理的一些细节上好像比较清楚了,但是内核是如何使用内存的还是有一些混淆。也产生了一些疑问,在内核中内存的正确打开方式是什么呢?

内核地址空间划分

首先我们需要搞情况内核的地址空间,不同地址空间的内存的使用方式是不同。

flowchart LR A[直接映射] B[vmalloc] C[持久映射] D[固定映射] A -.- B -.- C -.- D
内核中的地址空间划分

内核的地址空间被划分为直接映射区、vmalloc区、持久映射区和固定映射区。

  • 直接映射区: 提供了线性的地址映射关系,位于该区域的虚拟地址可以通过减去固定的地址偏移的到物理内存地址。虽然能够直接计算出地址,但是访存时还是需要通过页表+MMU实现地址转换,只是该部分虚拟地址空间的页表已经在内核初始化阶段就已经建立好了。
  • vmalloc区: 通过vmalloc分配,在vmalloc区域中找到一片连续虚拟地址空间,然后分配一些物理页帧(优先分配高端内存),并在页表建立起映射关系,以实现分配逻辑上连续但是物理上不连续的大块内存。
  • 持久映射区: 通过kmap建立起虚拟地址到物理页帧的映射,持久映射的作用就是满足访问高端内存的需要,持久映射区的虚拟地址就像一排插槽,每个插槽可以通过kmap映射到一个高端内存页帧,当插槽用完时kmap就会陷入睡眠等待可用插槽。那么,kmap可以建立到低端内存的映射吗?答案是no,kmappage指针为参数,如果page指针对应的页帧属于低端内存则不会建立插槽到物理页帧的映射,而是直接通过线性地址映射返回虚拟地址。
  • 固定映射区: 通过kmap_atomic建立,其原理和kmap类似,但是在插槽的设计上固定映射区的插槽以per-cpu的形式被划分,并且每个cpu拥有的插槽的数目和用途也在编译时被指定,因此kmap_atomic建立映射时需要指定具体的映射去覆盖,不会出现插槽数量不足导致睡眠。

内核中使用内存的正确方式

因此在内核中访问低端内存岂不是直接使用虚拟地址就可以了?不需要经过伙伴系统?似乎是这样的,但是这样的做法很不规范,访问和修改一个还在伙伴系统中的页帧内容或者他人申请的内存是有问题的。

NOTE: 不管使用什么虚拟地址,页表和MMU都是绕不开的

我个人理解访问内存还是依靠使用内核提供的一些接口。目前已知的有:

  • kmalloc: 通过slab分配器分配小尺寸的内存对象,由slab分配器向伙伴系统申请内存进行细化的管理。这里似乎没有主动建立地址映射,这是因为slab分配器不会申请高端内存和DMA内存,只会使用NORAML内存,其地址映射在页表中早已存在,有的文章没有指出这一点只是说从伙伴系统系统分配了内存,容易产生这种疑惑。
  • vmalloc: 从伙伴系统中分配多个不连续的页帧,并建立其vmalloc区域地址到物理页帧的映射,需要注意的是vmalloc虽然以字节为单位申请内存分配,但是实际上其分配的物理内存以页帧为单位,因此不要使用vmalloc分配小块内存,会造成浪费。另外为了管理vmalloc的地址空间,需要分配一些小的数据结构是通过kmalloc完成的。
  • alloc_pages_node & kmap: 还有一种方式则是通过主动从伙伴系统申请分配高端内存并使用kmap建立页表映射的方式。
  • alloc_pages_node & kamp_atomic: 用于特殊用途的高端内存映射 or 在中断上下文这种不允许睡眠的场景使用。才疏学浅,具体的使用场景还没研究过。

标签:正确,映射,虚拟地址,内核,kmap,vmalloc,内存
From: https://www.cnblogs.com/wodemia/p/17749505.html

相关文章

  • Hackintosh最简单且正确的USB定制方法
    一,使用USBToolBox定制https://github.com/USBToolBox请下载tool和kext,推荐在win下打开定制工具,定制过程非常简单,使用USB2.0和USB3.0各一个U盘,把所有的接口都插一遍,然后导出map.kext,将该kext和之前下载的另一个kext,总共两个kext放入efi加载并重启系统。二,使用hackintool完善使用usb......
  • python查看占用系统内存
    importosimportpsutilinfo=psutil.virtual_memory()print(u'cpu个数:',psutil.cpu_count())print(u'电脑总内存:%.4fGB'%(info.total/1024/1024/1024))print(u'当前进程的内存使用:%.4fGB'%(psutil.Process(os.getpid()).memory_info().rs......
  • 正确安装PaddleOCR的方法
     paddleocr安装起来太费劲了pipinstallpatch-ngpipinstallpaddleocr --use-pep517  (失败)1.首先去github下载:https://github.com/PaddlePaddle/PaddleOCR,然后找个文件夹解压。(从CSDN中点开链接时会提供加速功能,跳转到了https://gitcode.net/mirrors/paddlepaddle/padd......
  • 内存管理中的关键数据结构
    前言在谈Linux内存管理框架之前需要了解NUMA,NUMA是非一致性内存访问(Uon-UniformMemoryAccess)的缩写,与之相反的是一致性内存访问UMA。在多核的UMA架构的机器上,CPU视角下所有的内存都是均匀的,不同CPU访问同一块内存的延迟是相同;而在NUMA架构的机器上内存被划分为不同的区域,对CP......
  • 迁移类型与内存碎片
    前言在伙伴系统中长时间的内存分配之后很容易造成内存碎片,即物理内存总量不少但是无法合并为大的连续内存块。而在现代CPU中提供了hugepage的可能,可以分配超大块的page,在TLB中使用更少级的地址转换操作。一个page覆盖了更大的地址范围,大幅度的提高了TLB的命中概率。对于内存密集......
  • linux内核升级和内核源码编译
    一、ubuntu通过命令安装内核版本1、检查原系统内核版本uname-r2、搜索可用linux内核版本apt-cachesearchlinux|greplinux-headers3、通过apt命令安装内核apt-getinstall linux-headers-5.4.0-80-generic linux-image-5.4.0-80-generic4、安装成功后查看/boot目录......
  • 如何正确使用多线程和锁机制来构建可靠的程序
    本文分享自华为云社区《确保并发执行的安全性:探索多线程和锁机制以构建可靠的程序》,作者:LionLong。在当今计算机系统中,多线程编程已成为常见的需求,然而,同时也带来了并发执行的挑战。为了避免数据竞争和其他并发问题,正确使用适当的锁机制是至关重要的。通过阅读本文,读者将了解到......
  • PHP内核的学习--创建PHP扩展
    开始看PHP内核也有一段时间了,现在开始边学边总结,今天就总结一下如何创建自己的PHP扩展。我的环境如下:系统:Ubuntu14.04php版本:5.5.19参考摘录:用C/C++扩展你的PHPPHP取得成功的一个主要原因之一是它拥有大量的可用扩展。web开发者无论有何种需求,这种需求最有可能在PHP发行包里......
  • 基于 Linux、C++实现的高性能内存池
    1.引入内存池的意义  内存池(MemoryPool)是一种内存分配方式,又被称为固定大小区块规划(fixed-size-blocksallocation)。通常我们习惯直接使用new、malloc等API申请分配内存,但是这种方式非常容易产生内存碎片,早晚都会申请内存失败。并且在比较复杂的代码或者继承的屎山......
  • openGauss学习笔记-92 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-M
    openGauss学习笔记-92openGauss数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用MOTSQL覆盖和限制MOT设计几乎能够覆盖SQL和未来特性集。例如,大多数支持标准的PostgresSQL,也支持常见的数据库特性,如存储过程、自定义函数等。下面介绍各种SQL覆盖和限制。92.1不支持......