2487|2

544

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

《Linux内核深度解析》--内存管理 [复制链接]

本帖最后由 dirty 于 2025-1-5 13:24 编辑

      本篇梳理阅读笔记学习内存管理章节。

内存管理架构

      内存管理架构分为用户空间、内核空间和硬件三个层面。

用户空间

      应用程序使用malloc()申请内存,使用free()释放内存。这个是我们很熟悉经常用到的,通常是配对使用。

内核空间

内核空间的基本功能

      虚拟内存管理负责从进程的虚拟地址空间分配虚拟页,sys_brk用来扩大或收缩堆,sys_mmap用来在内存映射区域分配虚拟页,sys_munmap用来释放虚拟页。内核使用延迟分配物理内存的策略。页分配器负责分配物理页,当前使用的页分配器是伙伴分配器。内核空间提供了把页划分成小内存块分配的块分配器,提供分配内存的接口kmaloc()和释放内存的接口 kfree(),支持3种块分配器:SLAB分配器、SLUB分配器和SLOP分配器。

内核空间的扩展功能

      不连续页分配器提供了分配内存的接口vmalloc和释放内存的接口vfee,在内存碎片化的时候,申请连续物理页的成功率很低,可以申请不连续的物理页,映射到连续的虚页,即虚拟地址连续而物理地址不连续。

硬件层面
      处理器包含一个称为内存管理单元(Memory ManagementUnit,MMU)的部件,负责把虚拟地址转换成物理地址。

 

内存映射
      内存映射是在进程的虚拟地址空间中创建一个映射,分为以下两种。通常把文件映射的物理页称为文件页,把匿名映射的物理页称为匿名页。

●文件映射:文件支持的内存映射,把文件的一个区间映射到进程的虚拟地址空间,数据源是存储设备上的文件。

●匿名映射:没有文件支持的内存映射,把物理内存映射到进程的虚拟地址空间,没有数据源。

      内存映射的原理如下。

①创建内存映射的时候,在进程的用户虚拟地址空间中分配一个虚拟内存区域。

②Linux内核采用延迟分配物理内存的策略,在进程第一次访问虚拟页的时候,产生缺页异常。如果是文件映射,那么分配物理页,把文件指定区间的数据读到物理页中,然后在页表中把虚拟页映射到物理页;如果是匿名映射,那么分配物理页,然后在页表中把虚拟页映射到物理页。

      内存管理子系统提供了以下常用的系统调用。

(1)mmap()用来创建内存映射。

(2)mremap()用来扩大或缩小已经存在的内存映射,可能同时移动。

(3)munmap()用来删除内存映射。

(4)brk()用来设置堆的上界。

(5)remap_file_pages()用来创建非线性的文件映射。

(6)mprotect()用来设置虚拟内存区域的访问权限。

(7)madvise()用来向内核提出内存使用的建议,应用程序告诉内核期望怎样使用指定的虚拟内存区域,以便内核可以选择合适的预读和缓存技术。

      在内核空间中可以使用以下两个函数。
(1)remap_pf_range把内存的物理页映射到进程的虚拟地址空间,这个函数的用处是实现进程和内核共享内存。

(2)io_remap_pfrange把外设寄存器的物理地址映射到进程的虚拟地址空间,进程可以直接访问外设寄存器。

      书籍这一章讲了差不多三百页,内存管理底层这块讲的也比较详细,面面俱到去梳理学习还是有些浩繁,有需要部分可以作为参考书籍重点查阅。作为Linux应用,了解下用户空间使用以及内核空间、硬件层面的基本原理 会加深对Linux内核的理解,当然,经常用得到的内存管理方面API还是应该熟记、熟用。

 

应用

     下面是mmap、munmap内存映射创建与解除应用代码。

  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <fcntl.h>
  • #include <unistd.h>
  • #include <sys/mman.h>
  • #include <sys/stat.h>
  • #include <string.h>
  • int main() {
  • int fd;
  • struct stat sb;
  • char *map, *p;
  • int i;
  • char c;
  • // 打开文件
  • fd = open("try.txt", O_RDWR);
  • if (fd == -1) {
  • perror("open");
  • exit(EXIT_FAILURE);
  • }
  • // 获取文件大小
  • if (fstat(fd, &sb) == -1) {
  • perror("fstat");
  • close(fd);
  • exit(EXIT_FAILURE);
  • }
  • // 将文件映射到内存
  • map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  • if (map == MAP_FAILED) {
  • perror("mmap");
  • close(fd);
  • exit(EXIT_FAILURE);
  • }
  • printf("mmap 将文件映射到内存 OK\r\n");
  • // 关闭文件描述符,因为文件已经映射到内存
  • close(fd);
  • // 处理文件内容(例如,将所有字母转换为大写)
  • p = map;
  • for (i = 0; i < sb.st_size; i++) {
  • c = *p;
  • if (c >= 'a' && c <= 'z') {
  • *p = c - 'a' + 'A';
  • }
  • p++;
  • }
  • printf("将所有字母转换为大写完成\r\n");
  • // 解除映射
  • if (munmap(map, sb.st_size) == -1) {
  • perror("munmap");
  • exit(EXIT_FAILURE);
  • }
  • printf("munmap 解除映射 OK\r\n");
  • return 0;
  • }

      下面是运行情况,可以看到写入前文本小写字母转为大写字母,内存映射创建与解除均成功。

 

      本篇对内存管理有了初步梳理学习并小试牛刀,主要是学以致用,活学活用,有所取舍,后面继续学习与分享。

最新回复

Linux内核的内存管理本身就是比较复杂的玄学   详情 回复 发表于 2025-1-6 07:35
点赞 关注
个人签名

保持热爱


回复
举报

7016

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

Linux内核的内存管理本身就是比较复杂的玄学

点评

是会有些复杂  详情 回复 发表于 2025-1-6 21:24
 
 

回复

544

帖子

0

TA的资源

纯净的硅(初级)

板凳
 
Jacktang 发表于 2025-1-6 07:35 Linux内核的内存管理本身就是比较复杂的玄学

是会有些复杂

 
个人签名

保持热爱

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
报名最后一周!2025 英飞凌消费、计算与通讯创新大会-北京站
会议时间:3月18日(周二)09:30签到
参会奖励:电动螺丝刀套装、户外登山包、京东卡

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表