• linux内存概念理解


    目录

    内核空间

    内核空间的扩展功能

    硬件层面

    ARM64虚拟地址空间划分

    进程的用户虚拟地址空间

    内存布局

    物理地址空间

    内存映射


    内核空间

    1)内核空间的基本功能
     虚拟内存管理,负责从进程的虚拟地址空间分配虚拟页,
        sys_brk用来扩大或收缩堆,
        sys_mmap用来在内存映射区域分配虚拟页
        sys_munmap用来释放虚拟页;

    2)内核延迟分配物理内存的策略:进程第一次访问虚拟内存的时候,触发页错误异常
    页错误异常处理程序从页分配器申请物理页,在进程的页表中把虚拟页映射到物理页。

    3)页分配器负责分配物理页,当前使用的页分配器是伙伴分配器

    4)内核空间把页划分成小块内存,提供分配内存的接口kmalloc和释放内存的接口kfree
        支持slab slub slob

    5)在内核初始化过程中,页分配器没有准备好,需要使用临时的引导内存分配器分配内存

    内核空间的扩展功能


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

    2)每处理器内存分配用来为每处理器变量分配内存

    3)连续内存分配器(Coutiguous Memory allocator ,CMA)用来给驱动程序预留一段连续的内存,当驱动程序不用的时候,可以给进程使用;当驱动程序使用的时候,
    把进程占用的内存通过页回收或迁移的方式让出来,给驱动程序使用。

    4)内存控制组 用来控制今年初占用的内存资源

    5)内存碎片化时,找不到连续的物理页,内存碎片整理通过迁移的方式得到连续的物理页。

    6)内存不足的时候,页回收负责回收物理页,对于没有后备存储设备支持的匿名页,把数据换出到交换器,然后释放物理页;
        对于有后备存储支持的文件页,把数据写回存储设备,然后释放物理页。

    7)如果页回收失败,内存耗尽杀手,选择进程杀掉。


    硬件层面

    MMU内存管理单元,负责把虚拟地址转化成物理地址
    TLB页表缓存,保存最近使用的页表映射,避免每次把虚拟地址转换成物理地址都需要查询内存中的页表。
    一级缓存 二级缓存,解决处理器与内存速度不匹配问题。
    为了支持并行地取指令和取数据,一级缓存分为数据缓存和指令缓存。 

    ARM64虚拟地址空间划分


    1、虚拟地址的最大宽度是48位
    2、内核虚拟地址[0XFFFF 0000 0000 0000 ,OXFFFF FFFF FFFF FFFF]
    3、用户虚拟地址[0x0000 0000 0000 0000 ,0X0000 FFFF FFFF FFFF]
    4、内核虚拟地址和用户虚拟地址的宽度相同
    5、所有进程共享内核虚拟地址空间,每个进程有独立的用户虚拟地址空间
    6、同一个线程组的用户线程共享用户用户虚拟地址空间,内核线程没有用户虚拟地址空间。

    进程的用户虚拟地址空间


    1,代码段数据段和未初始化数据段
    2、动态库代码段,数据段和未初始化数据段
    3、存放动态生成的数据 堆
    4、存放局部变量和函数调用的栈
    5、存放栈底部的环境变量和参数字符串
    6、把文件区间映射到虚拟地址空间的内存映射区域。

    为了使缓冲区溢出攻击更加困难,内核支持为内存映射区域、栈和堆随机的起始地址。进程是否使用虚拟地址空间随机化,由以下两个因素共同决定
    1、进程描述符的成员personaliy是否设置ADDR_NO_RANDOMIZE
    2、全局变量randomize_va_space:0表示关闭虚拟地址空间随机化;1表示使内存映射映射区域和栈的起始地址随机化;2表示内存映射区域、栈和堆起始地址随机化。

    可以通过/proc/sys/kernel/randomize_va_space修改


    内存布局

    自顶向下增长,起始地址是STACK_TOP - 栈的最大长度 - 间隙。默认启用内存映射区域随机化,需要把起始地址减去一个随机值。

    内核地址空间布局
    1、线性映射区域的范围是[PAGE_OFFSET,2^64-1],起始位置是内核虚拟地址空间一半。

    PAGE_OFFSET = 0xFFFFFFFFFFFFFFFF<<(VA_BIT-1) 

    虚拟地址=((物理地址 - PHYS_OFFSET)+ PAGE_OFFSET),其中PHYS_OFFSET是内存的物理地址

    2、vmemmap区域范围[VMEMMAP_START,PAGE_OFFSET),长度是VMEMMAP_SIZE=(线性映射区域长度/页长度 * page结构体的长度上限)
    3、PCI/IO区域范围是[PIC_IO_START,PCI_IO_END) 长度是16M,结束地址是PCI_IO_END=(VMEMMAP_START-2MB)
    4、固定映射区域的范围[FIXADDR_START,FIXADDR_TOP),长度是FIXADDR_SIZE,结束地址是FIXADDR_TOP = (PCI_IO_START-2MB)
    5、vmalloc区域范围是[VMALLOC_START,VMALLOC_END),内核镜像在此区域
    6、内核模块区域范围[MODULES_VADDR,MODULES_END],长度128M
    7、KASAN (动态的内存错误检查工具)影子区域的起始地址是内核虚拟地址空间的起始地址,长度是内核虚拟地址的1/8

    物理地址空间


    物理地址是处理器在系统总线上看到,使用精简指令集的处理器通常只实现一个物理地址空间


    外围设备和物理内存使用统一的物理地址空间,有些处理器架构把分配给外围设备的物理地址区域称为设备内存。


    处理器通过外围控制器的寄存器访问外围设备,分为控制寄存器、状态寄存器和数据寄存器三大类。
    处理器对外围设备寄存器的编制方式有两种:
    1、I/O映射方式
    2、内存映射方式


    程序只能通过虚拟地址访问外设寄存器, 
    ioremap 把外设寄存器的物理地址映射到内核虚拟地址空间
    io_remap_pfn_range()把外设寄存器的物理地址映射到进程的用户虚拟地址空间

    ARM64结构定义了两种内存类型
    正常内存:物理内存和只读寄存器(ROM)
        共享属性
            不可共享:只能被处理器的一个核使用
            内部共享:一个处理器的所有共享或者多个处理器共享
            外部共享:处理器和其他观察者(如DMA)共享
        缓存属性:用来定义访问时是否通过缓存处理器
    设备内存:分配给外围设备寄存器的物理地址区域
        共享属性总是外部共享
        缓存属性总是不可缓存

    内存映射


    在进程的虚拟地址空间中创建一个映射
    1)文件映射,把文件的一个区间映射到进程的虚拟地址空间,数据源是存储设备上的文件;通常把文件映射的物理页称为文件页。
    2)匿名映射,没有文件支持,把物理内存映射到进程的虚拟地址空间,没有数据源。把匿名映射的物理页称为匿名页。

    根据修改是否对其他进程可见和是否传递到底层文件,内存映射分为共享映射和私有映射
    共享映射:修改数据时,映射相同区域的其他进程可以看见,如果是文件支持的映射,修改会传递到底层文件。
    私有映射:第一次修改数据时会从数据源复制一个副本,然后修改副本,其他进程看不见,不影响数据源。

    两个进程可以使用共享的文件映射实现共享内存,匿名映射通常是私有映射,共享的匿名映射只可能出现在父进程和子进程之间。
    在进程的虚拟地址空间中,代码段数据段是私有的文件映射,未初始化数据段、堆和栈是私有的匿名映射。

    学习链接:

    kernel学习链接

     参考

    https://course.0voice.com/v1/course/intro?courseId=2&agentId=0

  • 相关阅读:
    基于储能电站服务的冷热电多微网系统双层优化配置(Matlab代码实现)
    .net core程序集常用操作封装
    CSS实现围绕按钮边框转圈的光线效果
    【微信小程序】遍历列表数据,循环使用canva生成图片并下载
    [数据结构C++实现]二叉搜索树
    Mysql8.0为什么取消了缓存查询的功能
    Linux_进程概念
    [springboot专栏]文件本地上传与提供访问服务
    STM32的光敏检测自动智能窗帘控制系统proteus设计
    监控与运维,主流it运维监控工具
  • 原文地址:https://blog.csdn.net/WANGYONGZIXUE/article/details/132783381