操作系统-四、内存管理(小林coding笔记)

2023-05-16

虚拟内存

        防止内存运行多个程序时崩溃。

把进程所使用的地址隔离开,让操作系统为每个进程分配一套独立的虚拟地址。操作系统会提供一种机制,将不同进程的虚拟地址和不同内存的物理地址映射起来。

内存分段

        程序时由若干逻辑分段组成的,不同的段有不同的属性,所以用分段的形式把这些段分离出来。

        虚拟地址由段选择因子段内偏移量组成。

 带来的问题:内存碎片、内存交换的效率低。

内存碎片主要分为内部内存碎片和外部内存碎片,但一般不会出现内部内存碎片。用swap空间解决外部内存碎片,将内存和硬盘进行空间交换。但这样很慢导致效率低。

内存分页

        分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。

分页不会产生外部内存碎片,但页内会出现内存浪费,导致内部内存碎片的现象。

分页机制下,虚拟地址分为页号和页内偏移两部分。

多级页表 节约空间          TLB 节约时间,把最常访问的页表项存储到访问更快的硬件中,成为页表缓存。

段页式内存管理

        先把程序分为多个有逻辑意义的段,再把每个段分成固定大小的页。地址结构就由段号、段内页号和页内位移组成。

Linux内存主要采用页式内存管理,但同时不可避免的涉及了段机制。

内存分配

        malloc()是c库里的函数,用于动态分配内存。

方式一通过brk()系统调用从堆分配内存,方式二通过mmap()系统调用在文件映射区域分配内存。

             

 malloc分配的是虚拟内存,在分配内存时,会预分配更大的空间作为内存池。

malloc(1)实际分配132K字节的内存。

brk()方式申请的内存,free释放内存时,没有把内存归还给操作系统而是缓存在malloc内存池中了,待下次使用;而mmap方式申请的内存会归还给操作系统。

频繁使用mmap分配内存,每次都要进行运行态的切换,还会发生缺页中断,导致CPU消耗大。

频繁使用brk分配内存,堆内将产生越来越多不可用的碎片,导致内存泄漏。

free函数会对传进的内存地址向左偏移16字节,分析出内存块的大小。

内存回收

        后台内存回收和直接内存回收;

        后台内存回收过程是异步的,不会阻塞进程的执行;若后台异步回收跟不上就开始直接回收,这个过程是同步的,会阻塞进程的执行。若仍然无法满足内存需求,那么就会触发OOM机制。

        OOM Killer机制根据算法选择占内存高的进程将其杀死。

可以回收的内存

        文件页:内核缓存的磁盘数据和内核缓存的文件数据;回收干净页的方式是直接释放内存,回收脏页的方式是先写回磁盘在释放内存。

        匿名页:这部分内存没有实际载体。通过Swap机制先把内存写到磁盘,再释放内存。

回收都是基于LRU算法,也就是优先回收不常访问的内存。

调整文件页和匿名页的回收倾向:在Linux里把swappiness的数值设置为0,这样更倾向于文件页的回收,减少磁盘I/O的操作。

内核定义了三个内存阈值来衡量当前剩余内存的情况:页高阈值、页低阈值、页最小阈值。

 橙色部分:执行内存回收,直到剩余内存大于高阈值。异步回收

红色部分:触发直接内存回收。

通过调节内存最小阈值类设置页低阈值和页高阈值。

NUMA架构下的内存回收策略

SMP架构:多个CPU处理器共享资源的电脑硬件架构,每个CPU地位平等。也称为一致存储访问结构(UMA),但用同一根总线访问内存,总线压力大。

NUMA架构将每个CPU进行了分组,每组用Node表示,每个Node有自己独立的资源,包括内存、IO等。每组之间可以通过互联模块总线通信。

 在NUMA架构下,某个Node内存不足时,系统可以从其他Node寻找空闲内存。

保护进程

        omm_badness()根据进程消耗的内存打分,消耗的内存越大越容易被杀掉,可以通过调整omm_score_adj的值改变得分结果。

        将omm_score_adj设置为-1000,进程就不会被杀掉。

避免预读失效和缓存污染

        Linux操作系统的缓存:对读取的文件数据缓存到页缓存中。

        MySQL的缓存:Innodb存储引擎设计了一个缓冲池,其属于内存空间。

传统LRU算法:访问的页在内存中,把该页对应的LRU链表节点移动到链表头部;不在内存中,把该页放到LRU链表头部还要淘汰末尾的页。

预读机制:操作系统出于空间局部性原理,提前将磁盘块后续的数据都加载到内存中。好处是减少了磁盘I/O次数。

预读失效:被提前加载来的页没有被访问,反而占用链表头部位置,导致淘汰热点数据。

改进:

        Linux实现了两个LRU表:活跃LRU链表(active list)和非活跃LRU链表

        MySQL在LRU链表上划分了两个区域:young和old区域。

将预读页加入到inactive list的头部,当预读页被访问时,才将页插入active list的头部。

缓存污染

        热点数据都被挤到非活跃链表了,就导致活跃链表被污染了。

改进:

        提高进入活跃LRU链表的门槛,保证热点数据不会被轻易替换掉。

        Linux在内存也被第二次访问时,才把页升级到活跃链表中。

        MySQL在内存页被第二次访问同时时间间隔超过1秒时才会升级到young区。

深入理解虚拟内存管理

        进程虚拟内存空间

 存放进程程序二进制文件中的机器指令的代码段

定义全局变量和静态变量的数据段和BSS段

用于动态申请内存的堆

存放动态链接库以及内存映射区的文件映射与匿名映射

存放函数调用过程中的局部变量和函数参数的栈

Linux进程虚拟内存空间

 

 进程虚拟内存空间的管理

         进程在内核中的描述符task_struct结构,每个进程都有唯一的mm_struct结构体,保证虚拟地址空间都是独立互不干扰的。

        通过fork()创建的子进程,其虚拟内存空间和父进程的虚拟内存空间是一模一样的,直接拷贝过来的。

        通过vfork或clone系统调用创建的子进程,是将父进程的虚拟内存空间以及相关页表直接赋值给子进程,也就是父子的虚拟内存空间是共享的,一样的,并不是一份拷贝。这样子进程就变成了线程

        是否共享地址空间几乎是进程和线程的本质区别。

        内核线程和用户态线程的区别是内核线程没有相关的内存描述符mm_struct;

划分用户态和内核态虚拟内存空间

         进程的内存描述符mm_struct结构体中的task_size变量定义了用户态地址空间和内核态地址空间的分界线。

        内核中用mm_struct结构体中的属性来定义虚拟内存空间的不同内存区域。

 内核管理虚拟内存空间

结构体vm_area_struct描述了虚拟内存空间

 虚拟内存区域的访问权限和行为规范

        vm_page_prot偏向于定义页这一级别的访问控制权限,可直接应用在底层表中。

        vm_flags偏向于定义整个虚拟内存空间的访问权限和行为规范。

 内存映射中的映射关系

        属性anon_vma关联匿名映射区;属性vm_file关联被映射的文件;vm_pgoff表示映射进虚拟内存中的文件内容在文件中的偏移。

结构体 vm_area_struct结构中有一个vm_ops用来指向针对虚拟内存区域的相关操作的函数指针。

组织关系

内核中通过一个双向 vm_area_struct结构中的双向链表将虚拟内存空间中的虚拟内存区域串联起来的。头指针存储在内存描述符struct mm_struct结构体中的mmap中;每个虚拟内存区域又通过struct vm_arrea_struct中的vm_mm指针指向所属的虚拟内存空间mm_struct;

还有一种红黑树用于高效的查找,每个VMA都是树的一个结点,红黑树的根结点存储在mm_rb中。

 二进制文件映射到虚拟内库空间

        通过函数load_elf_binary将ELF格式的二进制文件中的Section加载并映射到虚拟内存空降中。

内核虚拟内存空间

        内核态虚拟内存空间是所有进程共享的。

32位体系内核虚拟内存空间布局

        直接映射区:范围为 3G -- 3G + 896m这块连续的虚拟内存地址会映射到0-896M这块连续的物理内存上。

        直接映射区存放的内容:前1M被系统占用,之后的存放内核代码段、数据段、BSS段。还有进程相关的数据结构、内核栈。

        物理内存896M以上的区域被内核划分为ZONE_HIGHMEM区域,称为高端内存。通过动态映射的方式映射到128M大小的内核虚拟内存空间中。

        动态映射区:动态的一部分一部分的分批映射。

         永久映射区:建立与物理高端内存的长期映射关系。

        固定映射区:虚拟地址是固定的,被映射的物理地址是可以改变的。相当于一个指针常量。

        临时映射区:临时映射,用完就释放。

 64位体系内核虚拟内存空间布局

        64位下内核虚拟内存空间很大,不用精细管理,直接映射就可以了。

 

 物理内存地址

         内存也叫随机访问存储器(RAM)

        静态RAM(SRAM):用于CPU高速缓存L1、L2、L3,访问速度快,容量小,造价高;

        动态RAM(DRAM):用于常说的主存,访问速度较慢,容量较大,相对便宜。

 主存由一个个存储器模块组成,多个存储器模块连接到存储控制器上,就聚合成了主存。

         DRAM芯片的存储结构是二维矩阵,二维矩阵中存储的元素成为超单元。都有坐标地址。

         包含两个地址引脚,八个数据引脚。

DRAM芯片的访问

 CPU读写主存

 CPU和主存之间的数据交互是通过总线完成的,数据在总线的传送过程称为总线事务。

总线上传输的信号有地址信号、数据信号、控制信号。总线传输的地址为物理内存地址

IO bridge负责转换不同总线上的电子信号。

CPU从内存读数据

 存储控制器将物理地址转换为二维坐标,并广播给所有存储器模块。并依次从DRAM0到DRAM7读取相应的supercell。

 物理内存地址实际上是不连续的,因为这连续的八个字节实际上存储与不同的DRAM芯片上。

Linux物理内存管理

        物理内存划分为内存页,在内核中用struct page结构体进行管理。每个结构体定义了一个索引编号PFN,与struct page 一 一 对应。

物理内存模型

        FLATMEN平坦内存模型

        假设内存是地址连续的内存空间,内核将内存空间分为一页一页的内存块struct page,用一个数组来组织连续的的物理内存页。

 内核使用mem_map的全局数组来组织所有划分出来的内存页,计算逻辑就是基于mem_map数组进行偏移操作。

        DISCONTIGMEM非连续内存模型

平坦模型管理非连续内存时会造成内存空洞。

        在DISCONTIGMEM非连续内存模型中,内核将物理内存从宏观上划分成了一个个的结点node,每个结点管理一块连续的物理内存。

 每个节点中还是采用FLATMEM平坦内存模型来组织管理物理内存页。

        SPARSEMEM稀疏内存模型

DISCONTIGMEN内存模型中的每个node中的物理内存也不一定都是连续的。若node数目多了,开销变大。

SPARSEMEM稀疏内存模型核心思想是对粒度更小的连续内存块进行精细管理。管理单元称为section。

 物理内存热插拔

热插拔分为两个阶段:物理热插拔阶段和逻辑热插拔阶段。

SPARSEMEM内存模型中的每个men_section都可以在系统运行时改变offline和online的状态,当offline时,内核把这部分内存隔离开,然后将内存页迁移到其他内存上。

 内核将物理内存根据物理页是否可前移,划分为不可迁移页、可回收页、可迁移页。热拔出时,操作的都是可迁移的内存页,从而使内存顺利拔出。

物理内存架构

        从CPU访问物理内存的角度观察物理内存的架构。

        一致性内存访问UMA架构

多个CPU访问内存都要过总线,且距离相同,访问速度都是一样的,这种模式叫SMP,即对称多处理器

 优点:结构简单,访问速度一致。

缺点:总线压力会变大,CPU可用带宽减少;总线长度增加,访问延迟。

非一致性内存访问NUMA架构

        内存被划分为一个个内存结点,每个CPU都有自己的本地内存节点,本地内存不足时,需要跨节点访问其他内存节点。

 NUMA内存分配策略

       

 内核管理NUMA节点

        内核统一组织NUMA节点

内核使用了一个类型为struct pglist_data的全局数据node_data[]来管理所有的NUMA节点。

         NUMA节点描述符pglist_data结构

node_id表示NUMA节点的id;

struct page 类型的数组node_men_map包含了NUMA节点内所有的物理内存页;

node_start_pfn指向NUMA节点内第一个物理页的PFN;

node_present_pages用于统计NUMA节点内所有真正可用的物理页面数量;

 NUMA节点物理内存区域的划分

        

 ZONE_MOVABLE 是一个虚拟内存区域,该区域的物理页都是可以迁移的,主要为了防止内存碎片和支持内存的热插拔。

NUMA节点之间所包含的物理内存区域个数是不一样的。

 NUMA节点中内存规整与回收

        kswapd进程用于回收不经常使用的页面;

        kcompactd进程用于内存的规整避免内存碎片。

NUMA节点的状态

        NUMA节点多余一个,内核会维护一个位图node_states,用于维护各个NUMA节点的状态信息。

内核管理NUMA节点中的物理内存区域

        内核中描述和管理NUMA节点中物理内存区域的结构体是struct zone;

 物理内存区域中的预留内存

        每个物理内存区域struct zone为操作系统预留了一部分内存,用于内核的核心操作。

        内核不允许高位内存对低位内存的无限制挤压,每个内存区域可以根据各自的lowmen_reserve_ratio计算各自区域中的预留内存大小;也可以进行动态调整。

物理内存区域中的水位线

        内存资源紧张时应对方法:产生OOM、内存回收、内存规整。

内核为每个NUMA结点中的每个物理内存区域定制了三条指示内存容量的水线:WMARK_MIN(页最小阈值)WMARK_LOW(页低阈值)WMARK_HIGH(页高阈值)

 水位线的数值是以min_free_kbytes为基准分别计算出来的,用户也可以通过sysctl来动态设置这个参数。

要保证kswapd进程活动范围大一些,这样就减少了直接回收内存的可能。调整watermark_scale_factor重新计算水位线之间的间距。

物理内存区域中的冷热页

        热页:已经加载进CPU高速缓存中的物理内存页;

        冷页:还未加载进CPU高速缓存中的物理内存页;

内核关于冷热页的管理全部封装在struct per_cpu_pageset结构中。两个pre_cpu_pages结构分别管理冷页和热页。

内核5.0版本直接使用struct pre_cpu_pages的链表来集中管理系统中所有CPU高速缓存冷热页。

每种迁移类型都对应一个冷热页链表。

内核描述物理内存页

        Linux采用4KB作为标准物理内存页的大小:必须是2的整数次幂;4KB是磁盘块大小的整数倍,同时传输小块数据会更高效

        struct page结构是内核中访问最频繁的结构体,其中包含了大量的union结构,被用于同一块内存根据不同的场景保存不同类型数据的一种方式。

匿名页的反向映射

        从物理内存映射到虚拟内存,用于某个物理内存页需要进行回收或迁移,此时就要去找到这个物理页被映射到了哪些进程的虚拟地址空间,并断开他们的映射。

        内核可以直接检出page结构中的mapping指针的最低位来判断该物理内存到底是匿名页还是文件页。

内存回收相关属性

        内核为了将页面的使用频率这个因素加入进来,就引入了active链表和inactive链表。

回收优先级:inactive 链表尾部 > inactive 链表头部 > active 链表尾部 > active 链表头部。

因为匿名页的换入换出代价大,所以要优先替换文件页。对active链表和inactive链表按照匿名页和文件页进行了归类。(匿名页的active链表,inactive链表和文件页的active链表,inactive链表)

swappiness设置为0时,内核只会置换文件页,不会置换匿名页。

物理内存页属性和状态的标志位flag

        struct page中的flag字段的高8位用来表示struct page的定位信息,剩余低位表示特定的标志位。

 复合页compound_page相关属性

        巨型大页:通过两个或者多个物理上连续的内存页page组装成一个比普通内存页page更大的页。

        可减少缺页中断提高性能;所需要的页表项比普通页要少,加速内存访问;拷贝父进程的页表时更快。

 复合页中所有尾页都会指向首页从而组合成一个完整的复合页。

 Slab对象池相关属性

        slab好比一个对象池,内核中的数据结构对象都对应于一个slab对象池,用于分配固定类型对象所需要的内存。从伙伴系统申请一整页内存,然后划分为多个大小相等的小块内存被slab管理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

操作系统-四、内存管理(小林coding笔记) 的相关文章

随机推荐

  • 函数执行时堆栈的详细过程

    文章目录 1 函数示例2 main函数中局部变量入栈过程3 main函数调用sum函数参数压栈4 调用sum函数的准备5 调用sum函数6 sum函数执行结束7 处理sum函数的结果返回 1 函数示例 2 main函数中局部变量入栈过程 3
  • java get方式请求url

    public String sendGet String result 61 34 34 BufferedReader in 61 null 读取响应输入流 try 创建URL对象 java net URL connURL 61 new j
  • 做自动化项目的时候自由协议通信怎么做

    工业现场 xff0c 一些扫码枪 称重传感器的通信协议 xff0c 有可能是厂家自己规定的 比如下面我给大家看一段RFID设备的通信协议 xff0c 如果你不能理解它是在干什么 xff0c 那就要好好学习plc的自由协议通信 这边举一个典型
  • vue3 element-plus el-progress 圆形circle进度条 内置文字换行

    span class token operator lt span div span class token operator gt span span class token operator lt span el span class
  • 一文彻底搞懂激光雷达原理!

    点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 最近一直在搞激光雷达相关东西 xff0c 今天把了解的激光雷达知识做一个框架整理 xff0c 顺便梳理了一下行业里面激光雷达相关公司 xff0c
  • 基于深度学习网络 在可穿戴式机器人中使用IMU实现人体活动实时识别

    可穿戴式外骨骼机器人已成为支持人类运动的一种新兴高科技产品 xff0c 能够在人体康复训练 日常活动和制造任务中提供必要的运动支持 xff0c 而搭建高精度 低延迟的人体活动识别系统 xff0c 能够帮助可穿戴式机器人快速准确地识别人体活动
  • DAY19-20 PX4入坑成功

    这几天在研究科学上网 xff0c 我就不写出来了 总之 xff0c 我把PX4拉到了自己的电脑上 在入门的过程中 xff0c 我根据自己以前的学习习惯 xff0c 开始大面积地搜集教程视频 xff0c 可惜并没有 xff01 这下我瞬间没招
  • 记一次C++ std::cout未定义及大量报错处理

    原因是什么并不清楚 但无论怎么处理 xff0c cout lt lt xxxxx 都会报 cout 未定义 xff0c 并且强行编译会一直报错 我最终处理方法是把MinGW给卸载 xff0c 然后重新下载安装 结果是此方法完全可行
  • ubuntu16.04 针对rosdep init初始化报错的解决方案(一针见血版)

    Ubuntu16 04 ros安装以及出现的问题 一 更换国内源 二 添加ROS源 三 添加密钥 四 安装ROS 五 初始化ROS 一 更换国内源 先复制一份源文件 再更换源地址 sudo cp etc apt sources list e
  • Linux使用gcc编译报错对pthread_create未定义的引用

    在包含pthread h头文件后 还是报错未定义的引用 span class token operator span tmp span class token operator span cc6zqi5F span class token
  • 狂神说java java基础篇 学习笔记

    java基础的视频内容笔记都在这了前言等字数非常长的章节 xff0c 使用了AI语音识别成文字后修改的 xff0c 有错漏欢迎提出面对对象模块的按照自己的理解进行了内容修改 xff0c 可以对比原视频内容理解 xff0c 如有建议欢迎提出
  • 解决Ubuntu没有wifi图标的问题

    在配置过程中输入命令后就没有wifi图标了 xff0c 不能上网了 xff08 可能是删除了网卡驱动 xff09 后续使用命令查询网卡 hardware of Internet 状态 lshw C network 查看网卡状态发现 无线网被
  • 2022-11-15日Linux安装csitools问题及解决办法

    问题一 xff1a 执行完这三步后电脑没有wifi图标了 xff0c 不能联网了 sudo modprobe r iwldvm iwlwifi mac80211 sudo modprobe r iwlwifi mac80211 cfg802
  • win10扩展c盘容量(2022-11-17)亲测可用

    个人经验 xff1a 想要通过右键我的电脑 管理 磁盘管理 xff0c 将紧挨着C盘的E盘压缩一100G扩展给C盘 这种做法试了不行 xff0c 即使让可用空间挨着C盘 xff0c C盘的扩展卷选项也是灰色的 解决 xff1a 下载傲梅分区
  • S-V信道模型理解

    Saleh和Valenzuela提出的S V信道模型是基于大量室内信道测试构建的 xff0c 更加符合室内真实路径的传播规律 xff0c 可以用来进行信道建模与仿真 下图显示了具有多簇射线的S V信道模型 xff0c 该模型中多径以簇形式达
  • wifi收发数据包分析

    根据802 11n协议WIFI每次发送64字节数据 Intel5300网卡接收的数据包大小为213字节或者393字节或者573字节 说明接受的数据包包含多个发送的包 猜想每个数据包是由多个主体重复加上固定的标志位组成 x 61 1 2 3
  • 清华大学 | 摄像头-激光雷达的时空在线集成标定方法

    点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 后台回复 多模态综述 获取论文 xff01 后台回复 ECCV2022 获取ECCV2022所有自动驾驶方向论文 xff01 后台回复 领域综述
  • 操作系统-硬件结构(小林coding笔记)

    控制和管理整个计算机系统的硬件和软件资源 xff1b 提供给用户和其他软件方便的接口和环境 xff1b 主要包括进程管理 内存管理 文件系统 设备管理和网络系统 图灵机的工作方式 基本思想就是用机器模拟人类用纸笔进行数学运算的过程 主要包含
  • 操作系统-三、操作系统结构(小林coding笔记)

    3 1Linux内核和Windows内核 Windows和Linux是常见的两款操作系统 xff0c 操作系统最核心的东西就是内核 内核 内核作为应用连接硬件设备的桥梁 内核的四个基本功能 xff1a 进程调度 内存管理 硬件通信 系统调用
  • 操作系统-四、内存管理(小林coding笔记)

    虚拟内存 防止内存运行多个程序时崩溃 把进程所使用的地址隔离开 xff0c 让操作系统为每个进程分配一套独立的虚拟地址 操作系统会提供一种机制 xff0c 将不同进程的虚拟地址和不同内存的物理地址映射起来 内存分段 程序时由若干逻辑分段组成