linux内存管理学习总结

news/2024/11/4 23:16:51/文章来源:https://www.cnblogs.com/lztutumo/p/18526935

一、内存寻址

1.1 逻辑地址、线性地址、物理地址的概念

1.2 逻辑地址转换线性地址步骤

1.3 线性地址到物理地址的转换

二、内存管理

2.1 引导内存分配器阶段

2.2 内存管理子系统

2.3 32位架构的地址空间划分

2.4 64位架构的地址空间划分

2.5 内核态的内存管理

2.6 用户态内存管理

2.7 一些内存的特殊用法

 

一、 内存寻址

  本节介绍linux内核如何进行芯片级的内存寻址;

  当处理器运行在实模式时,处理器执行指令直接使用物理地址;

  本节介绍在保护模式下,处理器运行linux内核时,是如何对内存进行寻址的;在保护模式下,处理器执行指令时首先看到的是逻辑地址,逻辑地址需要先转换成线性地址,线性地址再转换成物理地址,才能对内存进行访问;这个过程除了需要操作系统的处理,还需要借助硬件单元,比如逻辑地址到线性地址的转换,需要linux内核创建一个段描述符表,分段单元借助这个段描述符表把逻辑地址转换成线性地址;对于线性地址到物理地址的转换,软件上需要创建页表,硬件上需要MMU硬件单元,然后在访问内存的过程中,为了提高程序的访存效率,硬件上还引入了高速缓存和TLB缓存,本节介绍在这样的硬件结构下,运行linux内核时,处理器是如何进行内存访问的;

1.1    逻辑地址、线性地址、物理地址的概念

  逻辑地址,机器语言指令中使用的地址,也就是可执行文件中一条指令或者一个操作数的地址,cpu在取指令、取操作数时首先看到的就是逻辑地址;可执行文件被分为一个一个段,比如代码段、数据段、栈段、任务状态段、局部线程存储段等,因此一个逻辑地址就由一个16位的段标识符和32位偏移量组成;

  线性地址,操作系统使用的地址,在代码层面看到的指令地址和内存地址,就是线性地址;

  物理地址,最终访问存储单元,从地址总线发出去的就是物理地址;

1.2   逻辑地址转换线性地址步骤

  逻辑地址由一个16位的段标识符和32位偏移量组成,如下图所示,首先硬件把16位段选择符装入段寄存器(处理器为每个段都提供了段寄存器,cs、ss、ds、es、fs、gs),硬件通过段选择符找到对应的段描述符,这个段描述符保存在全局描述符表GDT或者局部描述符表LDT里面(描述符表是内核创建的,保存在内存的cpu_gdt_table数组里面,每个cpu有一个GDT,GDT的物理首地址放在gdtr控制寄存器中,当前正被使用的LDT地址和大小放在ldtr控制寄存器中),段描述符被硬件加载到cpu的非编程寄存器;段描述符里面包含段的首字节对应的线性地址,首字节的线性地址加上32位偏移量就得到这个逻辑地址对应的线性地址;需要说明的是在linux中,各段首对应的线性地址都是0,因此,在linux下逻辑地址总是和线性地址一致;

1.3    线性地址到物理地址的转换

  线性地址转换成物理地址的步骤,这个步骤通过查询页表来完成的,操作系统把线性地址划分成一个一个页,然后把物理内存也分成页大小一样的一个一个页框,页的内容可以保存在任意页框里面,页保存在哪个页框就记录在页表里面;页表由操作系统创建,每个进程都有一个页表,这个页表保存在内存里面,页表的首地址会保存在处理器的寄存器中,x86是保存在cr3寄存器,arm架构是保存在cp15协处理器的寄存器里面;内核提供了一组宏用于操作页表项,如pdg_index(addr)、pgd_offset(mm, addr)、pgd_page(pgd)等;

  由于线性地址庞大,为了减小页表的大小,操作系统一般会把页表组织成页目录的结构,比如linux的4级目录结构包括页全局目录、页上级目录、页中间目录、页表,对应的线性地址也会被分为4段,页全局目录索引、页上级目录索引、页中间目录索引、页表索引,查找过程大致是,首先从cpu的寄存器取出页全局目录的首地址,然后通过页全局目录的索引找到对应的页全局目录表项,这个表项里面里面保存了页上级目录的地址,找到页上级目录后,通过页上级目录索引,找到页上级目录中对应的表项,这个表项保存了页中间目录的地址,找到页中间目录后,通过页中间目录索引,找到页中间目录中对应的表项,这个表项保存了页表的地址,找到页表地址后,通过页表索引找到对应的页表项,这个页表项里面保存了对应页框的物理首地址,这个首地址加上线性地址中的偏移字段,就是线性地址对应的物理地址;需要指出的是,这些表项除了保存下一级的首地址,还保存了这个页对应的属性,包括present标志(页是否在主存中)、read/write标志(页或页表的存取权限)、user/supervisor标志(访问该页或页表需要的特权级)、PCD和PWT标志(控制硬件高速缓存处理页或页表的方式);

  由于页表保存在内存,每次查表都访问内存效率低,因此硬件上引入了页表的高速缓存TLB,类似于内存的高速缓存,把最近使用的页表缓存到TLB,处理器访问TLB的开销比访问内存小;

二、 内存管理

2.1 引导内存分配器阶段

  在内核的内存管理子系统还没初始化之前,分配内存的工作由引导内存分配器完成,早期使用的引导分配器是bootmem分配器,目前大部分使用的是memblock分配器;

  memblock分配器维护了一个数据结构,这个数据结构描述了哪些物理内存已经被使用,哪些物理内存可以被内核使用,数据结构如下,其中memory成员描述了内核可以访问的物理内存,reserved成员描述的是已经被使用的物理内存;

#include /linux/memblock.h
struct memblock {bool bottom_up;  /* is bottom up direction? */phys_addr_t current_limit;struct memblock_type memory;struct memblock_type reserved;
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAPstruct memblock_type physmem;
#endif
};

  memblock分配器的初始化函数是arm64_memblock_init,这个函数会解析设备树的内存信息节点/memory,这个节点描述了哪些物理内存可以被内核使用,解析这个节点的信息填充到memory成员中;从设备树读取保留内存的信息保存到reserved成员中,保留内存对应的节点是/memreserve和/reserved-memory;把内存镜像占用的物理内存范围添加到reserved成员中,这段内存可以被内核访问,但是已经被占用,所以memory和reserved两个成员都要添加;

memblock分配器对外提供的接口有memblock_add、memblock_remove、memblock_alloc、memblock_free;

2.2 内存管理子系统

       内存管理子系统使用节点、区域和页框三级结构描述物理内存;

  节点:在存储系统中,cpu访问不同区域的物理内存开销是不一样的,这种存储系统叫做非一致内存访问NUMA,内存管理子系统将物理内存分为不同的节点,同一个节点cpu访问内存的开销是相同的,节点使用pglist_data结构体描述该节点的内存布局,里面描述了这个节点包含的区域信息,以及这个节点包含的物理页框信息;

  区域:计算机体系结构有硬件的制约,有的外设使用DMA只能对RAM的前16M寻址,32位系统里面,内核空间的虚拟地址只有1G大小,如果RAM大于1G,那么内核的1G线性地址空间就无法覆盖所有RAM区域,基于这个考虑,内存管理系统将节点里面的内存分为DMA区域、NORMAL区域、高端内存区域,DMA区域:包含低于16MB的物理页框,NORMAL区域:直接映射到内核虚拟地址空间的区域,虚拟地址和物理地址是线性映射的关系,只差一个偏移,是否使用页表,不同处理器实现不同,MIPS处理器不需要页表,ARM处理器需要使用页表;高端内存区域:32位处理器才有这个区域,这个区域是由于RAM大于1G,导致内核1G的虚拟地址无法覆盖到,64位处理器就没有这个区域,因为内核的虚拟地址空间足够大;描述区域的数据结构是;

  页框:内存管理子系统以页框为单位对物理内存进行管理,描述页框的数据结构是page,记录页框的当前状态,比如该页框属于哪个进程的页、是否空闲、属于哪个区域、是否包含内核代码还是内核数据:

  分区页框分配器:

 

  内核管理子系统使用页分配器管理物理页,当前使用的页分配器是伙伴分配器;伙伴分配器就是把物理页框分成11个块链表组成,每个链表块大小不一样,链表中块大小是一样的,各链表块大小都是2的幂次方大小1、2、4、8、16,每个块中物理页框都是物理地址连续的;请求和释放页框以操作链表为单位,请求块过程中如果操作的块比请求的页框大,那么会将块进行拆分,拆分后剩余的页框会插入另一个小块链表中,如果拆分的块可以和其他块构成伙伴关系,那么还会进行块的合并操作,释放块时也会进行伙伴块合并已经块迁移链表的动作;请求和释放页框常用的函数有alloc_pages(gfp_mask, order)、alloc_page(gfp_mask)、__get_free_pages(gfp_mask, 0)、__get_free_page(gfp_mask)、__get_zeroed_page(gfp_mask)、__get_dma_pages(gfp_mask, order);

2.3 32位架构的地址空间划分

       32位架构可使用的虚拟地址空间是4GB,前0~3GB是用户空间使用,3~4GB是内核空间使用;3GB+896MB这段地址是线性映射区,也就是低端内存区(包括DMA和NORMAL区),其中内核页表swapper_pg_dir和内核可执行文件存在这个区域开始的地方0xc0000000;接着是高端内存区,高端内存区里面有非连续内存映射区vmalloc、高端内存永久映射区、高端内存固定映射区;

2.4 64位架构的地址空间划分

       目前应用程序不需要64位那么大的内存需求,arm64处理器不支持完全的64位虚拟地址;实际虚拟地址的最大宽度是48位,用户空间访问是0x0000 0000 0000 0000~0x0000 FFFF FFFF FFFF,内核地址范围是0xFFFF 0000 0000 0000~0xFFFF FFFF FFFF FFFF;

  ARM64架构的内核地址空间布局如下图所示,最上面是线性映射区,长度是内核虚拟地址空间的一半,这部分区域虚拟地址和物理地址是线性关系;vmemmap区域是稀疏内存的page结构体数组的虚拟地址空间;PCI I/O区域是PCI设备的I/O地址空间;固定映射区域是编译时的特殊虚拟地址,编译的时候是一个常量,在内核初始化的时候映射到物理地址;vmalloc区域是非线性映射区,内核使用vmalloc分配该区域的内存,内核镜像也在这个区域;内核模块区域是内核模块使用的虚拟地址空间;最后是KASAN内存检测工具使用的区域;

2.5 内核态的内存管理

       Linux操作系统的内存管理子系统是运行在内核态的,用户态申请内存最终分配物理页框时也是在内核态完成的;

  从请求内存的大小来分,内存管理子系统提供两种内存分配方式,一种是以页框大小倍数为单位申请和释放内存,这种方式基于分区页框分配器(当前用的是伙伴管理系统)实现;另一种是任意字节大小内存的分配,这种方式基于slab分配器实现,slab分配器使用伙伴分配器获得一块连续的物理页框,然后把这个页框进行切割,分成一个个固定大小的内存对象,请求内存时,将大小适合的内存对象分配给请求者;

  从请求的物理内存是否连续来区分,直接使用伙伴系统请求的页框是物理地址连续的,使用slab分配器申请的内存也是物理地址连续的;使用vmalloc申请的内存是不保证物理地址连续的;

  需要说明的是,内存管理子系统将物理内存分为三个区域:DMA区、NORMAL区以及高端内存区;使用伙伴系统申请连续页框时,可以使用标志指定从哪个区域请求页框;使用slab分配器请求页框也是一样的,可以使用标志指定从哪个区域请求内存;__GFP_DMA、__GFP_HIGHMEM;

  slab分配器:核心思想是把申请和释放的内存当作对象来处理,如下图所示slab分配器把整块内存分为一个个小的内存对象,并且采用面向对象的思想,为这些对应提供对应的构造和析构函数;对象类型比如内核专用的对象有进程描述符、内存描述符、文件描述符等,这些都是常用对象,slab分配器预先分配好这些对象,当内存请求这些对象时,就可以直接提供,提高了内存申请效率;还有通用的内存对象,这些对象以2的幂次方大小提供,从普通区域分配页的内存对象名称是kmalloc-<size>,从DMA区域分配页的对象名称是dma-kmalloc-<size>,通过命令cat /proc/slabinfo可以查询这些通用对象;

  基于slab分配器衍生出来的还有slub分配器和slob分配器,slab分配器由于数据结构复杂,本身的内存开销大,在物理内存使用量大的时候内存开销大,因此设计了slub分配器;由于slab分配器代码多、实现复杂,因此针对小内存的嵌入式系统设计了精简的slob分配器;

  非连续内存区管理:内核态的线性地址空间有一段vmalloc区间,这段区间用于映射非连续物理内存,调用vmalloc接口申请内存时,在这个区间找到一块大小合适的线性地址区间,然后内存管理子系统找到合适的物理页框,创建页表把线性地址和物理页框映射起来;每次调用vmalloc都调用get_vm_area()函数创建一个非连续内存区描述符,然后多次调用alloc_page接口从分区页框分配器申请物理页框,接着调用map_vm_area函数把线性地址和物理页框对应的物理地址映射起来;需要注意的是vmalloc接口优先从高端内存区请求页框,每次请求物理内存都是以页框为单位,也就是不管申请的内存大小是多少,至少都是4096字节大小,因此建议需要申请的内存大于一个页时才使用vmalloc;

2.6 用户态内存管理

       进程的用户虚拟地址空间包含以下区域:

  1、 代码段、数据段和未初始化数据段;

  2、 动态库的代码段、数据段和未初始化数据段;

  3、 动态内存:堆;

  4、 栈;

  5、 存放在栈底部的环境变量和参数字符串;

  6、把文件映射到虚拟地址空间的内存映射区;

  Linux通过线性区的方式来管理进程的用户态虚拟地址空间;比如堆是一个线性区、栈是一个线性区、代码段是一个线性区、数据段是一个线性区、对一个文件执行内存映射创建线性区、共享内存线性区等;

       线性区使用数据结构vm_area_struct表示,线性区数据结构包含在进程的内存描述符里面mm_struct;

       线性区映射的物理内存采用延迟分配的原则,在使用时才触发缺页异常处理来分配实际的物理页,比如代码段和数据段的访问,代码段和数据段一般是保存在硬盘这样的存储介质里面,进程通过文件映射的方式把可执行文件的代码段和数据段映射到进程的线性区,当cpu实际访问代码段和数据段的时候,内核才给代码段和数据段映射物理页框,然后把代码段和数据段从硬盘读到物理页框;

2.7 一些内存的特殊用法

  待总结~

参考博客:

https://blog.csdn.net/u012489236/article/details/106109251?spm=1001.2014.3001.5501

《ARM体系结构与编程》

《linux内核深度解析》

《深入理解linux内核》

本文仅学习总结以便更好地理解linux的内存管理,还有部分博客没有一一列上,如有侵权请联系删除

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/826860.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

https页面加载http资源的解决方法

https页面加载http资源的解决方法@目录1.报错如图2.项目背景3.网上的解决方案4.我的最终解决方案 1.报错如图2.项目背景我们的项目采用的全是https请求,而使用第三方文件管理器go-fastdfs,该文件管理器返回的所有下载文件的请求全是http开头的,比如http://10.110.38.253:110…

Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载

Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载@目录一、业务背景二、实现思路二、准备工作1.准备data模板.xlsx2.引入poi相关依赖,用于操作excel3.针对WorkBook+ZIP压缩输入/输出流,相关方法知识点要有所了解三、完整的项目代码四、可能遇到的问题错误场景…

macOS 解锁隐藏文件

不知道为什么,我用 VS Code 编译的 LaTeX 文档是隐藏的,导致我复制到其他地方都看不见这个文档。首先可以按下 Command + Shift + . 组合键显示隐藏文件。接下来可以用下面的命令取消隐藏的文件: chflags nohidden <file>如果你想重新隐藏的话,使用下面的命令: chfl…

Spring原理Boot

Spring原理 SpringBoot 1 Boot 1.1 Boot 骨架项目 如果是 linux 环境,用以下命令即可获取 spring boot 的骨架 pom.xml curl -G https://start.spring.io/pom.xml -d dependencies=web,mysql,mybatis -o pom.xml也可以使用 Postman 等工具实现 若想获取更多用法,请参考 curl …

0xGame 2024 [Week 2] 报告哈基米

0xGame 2024 [Week 2] 报告哈基米 新知识:Tupper(塔珀自指公式);Arnold Cat(猫映射) 下载文件是一个png图片,010打开查看 发现是倒着的pk转一下保存为zip文件,打开后是一个txt文件有两个地方有提示,一个是十六进制里面的Maybe You Need To Kown Arnold Cat?还有一个是…

告别 PPT 配图难题!Napkin.ai 轻松打造生动演示文档(文末免费送书)

还在为 PPT 配图发愁?Napkin.ai 来救场!它是强大的文本自动配图工具,能自动摘要文本、生成并自定义配图,下载方式多样。文中详细介绍其使用方法,包括注册、创建 Napkin、选择和设置配图等。此外,还有免费送书活动,关注、留言点赞就有机会获得《OpenAI API 接口应用实战》…

Origin pro 2024下载与安装

1、安装包 OriginPro 是由 OriginLab 公司开发的专业制图和数据分析软件,大部分科学研究的统计、作图、函数拟合等要求都可以满足,尤其适合曲线、曲面的图。它提供了上百种二维和三维绘图模板,而且允许用户自己定制模板。OriginPro 中的数据分析功能包括统计,信号处理,曲线…

20222323 2024-2025-1 《网络与系统攻防技术》实验四实验报告

1.实验内容 一、恶意代码文件类型标识、脱壳与字符串提取 对提供的rada恶意代码样本,进行文件类型识别,脱壳与字符串提取,以获得rada恶意代码的编写作者,具体操作如下: (1)使用文件格式和类型识别工具,给出rada恶意代码样本的文件格式、运行平台和加壳工具; (2)使用…

如何计算并联谐振电路中电感和电容的电流

(附:可以验证一下电容的容抗计算,假设在1kHz(其他频率电容值会变)时计算470uF的容抗为2x3.14x10^3 x470x10^-6约等于0.339欧)

C# windos服务的安装与卸载

注:需要使用管理员权限打开 使用命令窗口安装服务使用命令窗口卸载服务 使用 PowerShell安装服务 与命令窗口区别在于需要加上 ./ 卸载也是如此

【GiraKoo】WSLg,x11下鼠标显示超大问题对策

WSLg,x11下,显示鼠标尺寸过大的问题【GiraKoo】WSLg下鼠标显示超大问题对策 环境Windows 10,11 WSLg x11 4K显示屏现象在wslg下,打开Android Studio客户端,鼠标显示过大。原因 从环境猜测,应当是x11转发导致的问题。 对策在~/.bashrc中添加以下内容:export XCURSOR_SIZE=2…