当前位置: 首页 > news >正文

深入理解linux内核--内存管理

RAM的某些部分永久分配给内核,
来存放内核代码及静态内核数据结构。
RAM的其余部分称为动态内存,
这不仅是进程所需的宝贵资源,
也是内核本身所需的宝贵资源。

页框管理

Intel的Pentinum处理器可采用两种不同的页框大小:
4KB,4MB(如PAE被激活,则为2MB)。
Linux采用4KB页框大小作为标准的内存分配单元。
1.由分页单元引发的缺页异常很容易得到解释,
或由于请求的页存在但不允许进程对其访问,
或由于请求的页不存在。
第二种情况下,
内存分配器必须找到一个4KB的空闲页框,
并将其分配给进程。
2.虽然4KB,4MB都是磁盘块大小的倍数,
但绝大多数情况下,
当主存和磁盘之间传输小块数据时更高效。

页描述符

内核必须记录每个页框当前的状态。
如,内核必须能区分哪些页框包含的是属于进程的页,
哪些页框包含的是内核代码或内核数据。
类似地,内核还必须能确定动态内存中的页框是否空闲。
页框的状态信息保存在一个类型为page的页描述符中,
其中的字段如表所示:
类型名字说明
unsigned longflags一组标志。对页框所在的管理区进行编号。
atomic_t_count页框的引用计数器
atomic_t_mapcount页框中的页表项数量(没有则为-1)
unsigned longprivate可用于正使用页的内核成分
struct address_space*mapping当页被插入页高速缓存时使用。或当页属于匿名区时使用。
unsigned longindex作为不同的含义被几种内核成分使用。
struct list_headlru包含页的最近最少使用双向链表的指针
所有的页描述符存放在mem_map数组中。
每个描述符长度为32字节,
所以mem_map所需要的空间略小于整个RAM的1%。
virt_to_page(addr)宏产生线性地址addr对应的页描述符地址。
pfn_to_page(pfn)宏产生与页框号pfn对应的页描述符地址。
让我们较详细地描述以下两个字段:
_count页的引用计数器。如字段为-1,则相应页框空闲,并可被分配给任一进程或内核本身。如该字段值大于或等于0,则说明页框被分配给了一个或多个进程,或用于存放一些内核数据结构。page_count返回__count加1后的值,即该页的使用者的数目。
flags包含多达32个用来描述页框状态的标志。对每个PG_xyz标志,内核都定义了操纵其值的一些宏。通常,PageXyz宏返回标志的值,SetPageXyz和ClearPageXyz宏分别设置和清除相应的位。
标志名含义
PG_locked页被锁住。如,在磁盘I/O操作中涉及的页
PG_error在传输页时发生I/O错误
PG_referenced刚刚访问过的页
PG_uptodate在完成读操作后置位,除非发生磁盘I/O错误
PG_dirty页已经被修改
PG_lru页在活动或非活动页链表中
PG_active页在活动页链表中
PG_highmem页框属于ZONE_HIGHMEM管理区
PG_checked由一些文件系统使用的标志
PG_arch_1在80x86体系结构上没有使用
PG_reserved页框留给内核代码或没有使用
PG_private页描述符的private字段存放了有意义的数据
PG_writeback正使用writeback方法将页写到磁盘上
PG_nosave系统挂起、唤醒时使用
PG_compound通过扩展分页机制处理页框
PG_swapcache页属于对换高速缓存
PG_mappedtodisk页框中的所有数据对应于磁盘上分配的块
PG_reclaim为回收内存对页已经做了写入磁盘的标记
PG_nosave_free系统挂起、恢复时使用

非一致内存访问(NUMA)

习惯上,认为计算机内存是一种均匀,共享的资源。
在忽略硬件高速缓存作用的情况下,
期望不管内存单元处于何处,CPU处于何处,
CPU对内存单元的访问都需相同的时间。
可惜,
这些假设在某些体系结构上并不总是成立。
如,对某些多处理器Alpha或MIPS计算机,就不成立。Linux2.6支持非一致内存访问模型,
在这种模型中,
给定CPU对不同内存单元的访问时间可能不一样。
系统的物理内存被划分为几个节点(node)。
在一个单独的节点内,
任一给定CPU访问页面所需的时间都是相同的。
然而, 
对不同CPU,这个时间可能就不同。对每个CPU而言,
内核都试图把耗时节点的访问次数减到最少,
这就要小心地选择CPU最常引用的内核数据结构的存放位置。每个节点中的物理内存又可分为几个管理区。
每个节点都有一个类型为pg_data_t的描述符。
类型名字说明
struct zone[]node_zones节点中管理区描述符的数组
struct zonelist[]node_zonelists页分配器使用的zonelist数据结构的数组
intnr_zones节点中管理区的个数
struct page*node_mem_map节点中页描述符的数组
struct bootmem_data*bdata用在内核初始化阶段
unsigned longnode_start_pfn节点中第一个页框的下标
unsigned longnode_present_pages内存节点的大小,不包含洞(以页框为单位)
unsigned longnode_spanned_pages节点的大小,包括洞(以页框为单位)
intnode_id节点标识符
pg_data_t*pgdat_next节点内存链表中的下一项
wait_queue_head_tkswapd_waitkswapd页换出守护进程使用的等待队列
struct task_struct*kswapd指针指向kswapd内核线程的进程描述符
intkswapd_max_orderkswapd将要创建的空闲块大小取对数的值
同样,我们只关注80x86。
IBM兼容PC使用一致内存访问模型,
因此,
并不真正需要NUMA的支持。
然而,
即使NUMA的支持没有编译进内核,
Linux还是使用节点。
不过,
这是一个单独的节点,
它包含了系统中所有的物理内存。
故,pgdat_list指向一个链表,
此链表是由一个元素组成的。
这个元素就是节点0描述符,它被存放在config_page_data。在80x86结构中,
把物理内存分组在一个单独的节点中可能显得没用处;
但,这种方式有助于内核代码的处理具有可移植性。 

内存管理区

在一个理想的计算机体系结构中,
一个页框就是一个内存存储单元,
可用于任何事情:
存放内核数据和用户数据,缓冲磁盘数据等等。
任何种类的数据页都可存放在任何页框中。但实际的计算机体系结构有硬件的制约,
这限制了页框可使用的方式。
尤其是,Linux内核必须处理80x86体系结构的两种硬件约束:
1.ISA总线的直接内存存取(DMA)处理器有一个严格的限制:
它们只能对RAM的前16MB寻址、
2.在具有大容量RAM的现代32位计算机中,
CPU不能直接访问所有的物理内存,
因此线性地址空间太小。为应对这两种限制,
Linux2.6把每个内存节点的物理内存划分为三个管理区。
在80x86UMA体系结构中的管理区为:
ZONE_DMA包含低于16MB的内存页框
ZONE_NORMAL包含高于16MB且低于896MB的内存页框
ZONE_HIGHMEM包含从896MB开始高于896MB的内存页框
ZONE_DMA区包含的页框可由老式基于ISA的设备通过DMA使用。ZONE_DMA和ZONE_NORMAL区包含内存的"常规"页框,
通过把它们线性地址映射到线性地址空间的第4个GB,
内核就可直接进行访问。
相反,
ZONE_HIGHMEM区包含的内存页不能由内核直接访问,
尽管它们页线性地映射到了线性地址空间的第4个GB。
在64位体系结构上,
ZONE_HIGHMEM区总是空的。每个内存管理区都有自己的描述符。
类型名称说明
unsigned longfree_pages管理区中空闲页的数目
unsigned longpages_min管理区中保留页的数目
unsigned longpages_low回收页框使用的下界;同时也被管理区分配器作为阀值使用
unsigned longpages_high回收页框使用的上届;同时也被管理区分配器作为阀值使用
unsigned long[]lowmem_reserve指明在处理内存不足的临界情况下每个管理区必须保留的页框数目
struct per_cpu_pageset[]pageset用于实现单一页框的特殊高速缓存
spinlock_tlock保护该描述符的自旋锁
struct free_area[]free_area标识出管理区的空闲页框块
spinlock_tlru_lock活动以及非活动链表使用的自旋锁
struct list_headactive_list管理区中的活动页链表
struct list_headinactive_list管理区中的非活动页链表
unsigned longnr_scan_active回收内存时需扫描的活动页数目
unsigned longnr_scan_inactive回收内存时需扫描的非活动页数目
unsigned longnr_active管理区的活动链表上的页数目
unsigned longnr_inactive管理区的非活动链表上的页数目
unsigned longpages_scanned管理区内回收页框时使用的计数器
intall_unreclaimable在管理区中填满不可回收页时此标志被置位
inttemp_priority临时管理区的优先级
intprev_priority管理区优先级,范围在12和0之间
wait_queue_head_t*wait_table进等待队列的散列表,这些进程正在等待管理区中的某页
unsigned longwait_table_size等待队列散列表的大小
unsigned longwait_table_bits等待队列散列表数组大小,值为2^order
struct pglist_data*zone_pgdat内存节点
struct page*zone_mem_map指向管理区的第一个页描述符的指针
unsigned longzone_start_pfn管理区第一个页框的下标
unsigned longspanned_pages以页为单位的管理区的总大小,包括洞
unsigned longpresent_pages以页为单位的管理区的总大小,不包括洞
char*name指针指向管理区的传统名称:“DMA”,“NORMAL”,“HighMem”
每个页描述符都有到内存节点和节点内管理区的链接。
为节省空间,这些链接被编码成索引存放在flags字段的高位。
实际上,
刻画页框的标志的数目是有限的。
保留flags字段的最高位来编码特定内存节点和管理区号总是可能的。
page_zone接收一个页描述符的地址作为它的参数;
它读取页描述符中flags字段的最高位,
然后通过查看zone_table数组来确定相应管理区描述符的地址。
在启动时用所有内存节点的所有管理区描述符的地址初始化这个数组。当内核调一个内存分配函数时,
必须指明请求页框所在的管理区。
内核通常指明它愿意使用哪个管理区。为了在内存分配请求中指定首选管理区,
内核使用zonelist数据结构,
这就是管理区描述符指针数组。

保留的页框池

可用两种不同的方法来满足内存分配请求。
如有足够的空闲内存可用,
请求就会被立刻满足。
否则,必须回收一些内存,且将发出请求的内核控制路径阻塞,直到内存被释放。当请求内存时,
一些内核控制路径不能被阻塞--如,这种情况发生在处理中断或执行临界区内的代码时。
此时,
一条内核控制路径应产生原子内存分配请求。
原子请求从不被阻塞:
如没有足够的空闲页,则仅仅是分配失败而已。尽管无法保证一个原子内存分配请求决不失败,
但内核会设法尽量减少这种不幸事件发生的可能性。
为做到这一点,
内核为原子内存分配请求保留了一个页框池,
只有在内存不足时才使用。保留内存的数量(以KB为单位)存放在min_free_kbytes中。
它的初始值在内核初始化时设置,
并取决于直接映射到内核线性地址空间的第4个GB的物理内存的数量
--即,取决于包含在ZONE_DMA和ZONE_NORMAL内存管理区内的页框数目。
保留池的大小=sqrt(16*直接映射内存)(KB)
但,min_free_kbytes的初始值不能小于128也不能大于65536。
ZONE_DMA和ZONE_NORMAL内存管理区将一定数量的页框贡献给保留内存,
这个数目与两个管理区的相对大小成比例。
例,如ZONE_NORMAL管理区比ZONE_DMA大8倍,
则页框的7/8从ZONE_NORMAL获得。
1/8从ZONE_DMA获得。管理区描述符的pages_min存储了管理区内保留页框的数目。
这个字段和pages_low,pages_high一起还在页框回收算法中起作用。
pages_low总是设为pages_min的值的5/4,
pages_high总是被设为pages_min的3/2。

分区页框分配器

相关文章:

深入理解linux内核--内存管理

RAM的某些部分永久分配给内核, 来存放内核代码及静态内核数据结构。 RAM的其余部分称为动态内存, 这不仅是进程所需的宝贵资源, 也是内核本身所需的宝贵资源。页框管理 Intel的Pentinum处理器可采用两种不同的页框大小: 4KB&…...

SpringBoot热部署的开启与关闭

1、 开启热部署 &#xff08;1&#xff09;导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId> </dependency>&#xff08;2&#xff09;设置 此时就搞定了。。。 2、…...

k8s集群部署(使用kubeadm部署工具进行快速部署,相关对应版本为docker20.10.0+k8s1.23.0+flannel)

1. 安装要求 在开始之前&#xff0c;部署Kubernetes集群机器需要满足以下几个条件&#xff1a; 一台或多台机器&#xff0c;操作系统 CentOS7.x-86_x64硬件配置&#xff1a;2GB或更多RAM&#xff0c;2个CPU或更多CPU&#xff0c;硬盘20GB或更多可以访问外网&#xff0c;需要拉…...

20230729 git github gitee

1.gitee与gitHub概念&#xff1f; Gitee&#xff08;码云&#xff09;是开源中国社区推出的代码托管协作开发平台&#xff0c;支持Git和SVN&#xff0c;提供免费的私有仓库托管。Gitee专为开发者提供稳定、高效、安全的云端软件开发协作平台&#xff0c;无论是个人、团队、或是…...

php建造者模式

一&#xff0c;建造者模式&#xff0c;也叫做生成器模式&#xff0c;是创建设计模式的一种&#xff0c;它能将一个复杂的对象的创建过程分离开来&#xff0c;使你能够分步骤的创建对象。建造者模式也允许你使用相同的建造代码创造出不同类型和形式的对象。 建造者模式一般包括四…...

linux---》用户操作/su和sudo/普通权限/特殊权限/解压压缩/软件管理,rpm和yum/源码安装nginx

用户操作 ####创建用户####1 创建sa和sutdents组 groupadd sa groupadd students # 2 用户可以属于多个组&#xff0c;只能属于一个主组&#xff0c;附加组可以有多个 G useradd -u 5001 -g students -G sa -c "注释" -s /bin/bash lqz666 # 3 设置密码 passwd lqz6…...

tinkerCAD案例:20. Simple Button 简单按钮和骰子

文章目录 tinkerCAD案例&#xff1a;20. Simple Button 简单按钮Make a Trick Die tinkerCAD案例&#xff1a;20. Simple Button 简单按钮 Project Overview: 项目概况&#xff1a; This is a series of fun beginner level lessons to hone your awesome Tinkercad skills a…...

Java - 为什么要用BigDecimal?

&#x1f914;️为什么要用BigDecimal&#xff1f; 当然是因为使用Double计算&#xff0c;在某些对精度要求很高的场景下会出现问题&#x1f480;不信你看⤵️ Test void test12() {// 丢失精度double result 0.2 0.1;System.out.println(result); // 输出结果为 0.300000000…...

mac 删除自带的ABC输入法保留一个搜狗输入法,搜狗配置一下可以减少很多的敲击键盘和鼠标点击次数

0. 背景 对于开发者来说&#xff0c;经常被中英文切换输入法所困扰&#xff0c;我这边有一个方法&#xff0c;删除mac默认的ABC输入法 仅仅保留搜狗一个输入法&#xff0c;配置一下搜狗输入&#xff1a;哪些指定为英文输入&#xff0c;哪些指定为中文输入&#xff08;符号也可…...

JiaYu说:如何做好IT类的技术面试?

IT类的技术面试 面试IT公司的小技巧IT技术面试常见的问题嵌入式技术面试嵌入式技术面试常见的问题嵌入式软件/硬件面试题 JiaYu归属嵌入式行业&#xff0c;所以这里只是以普通程序员的角度去分析技术面试的技巧 当然&#xff0c;也对嵌入式技术面试做了小总结&#xff0c;友友们…...

RL 实践(6)—— CartPole【REINFORCE with baseline A2C】

本文介绍 REINFORCE with baseline 和 A2C 这两个带 baseline 的策略梯度方法&#xff0c;并在 CartPole-V0 上验证它们和无 baseline 的原始方法 REINFORCE & Actor-Critic 的优势参考&#xff1a;《动手学强化学习》完整代码下载&#xff1a;7_[Gym] CartPole-V0 (REINFO…...

Python numpy库的应用、matplotlib绘图、opencv的应用

numpy import numpy as npl1 [1, 2, 3, 4, 5]# array():将列表同构成一个numpy的数组 l2 np.array(l1) print(type(l2)) print(l2) # ndim : 返回数组的轴数&#xff08;维度数&#xff09; # shape&#xff1a;返回数组的形状&#xff0c;用元组表示&#xff1b;元组的元素…...

SpringBoot 如何进行 统一异常处理

在Spring Boot中&#xff0c;可以通过自定义异常处理器来实现统一异常处理。异常处理器能够捕获应用程序中抛出的各种异常&#xff0c;并提供相应的错误处理和响应。 Spring Boot提供了ControllerAdvice注解&#xff0c;它可以将一个类标记为全局异常处理器。全局异常处理器能…...

数据库索引优化与查询优化——醍醐灌顶

索引优化与查询优化 哪些维度可以进行数据库调优 索引失效、没有充分利用到索引-一索引建立关联查询太多JOIN (设计缺陷或不得已的需求) --SQL优化服务器调优及各个参数设置 (缓冲、线程数等)–调整my.cnf数据过多–分库分表 关于数据库调优的知识点非常分散。不同的 DBMS&a…...

Student and Teacher network(学生—教师网络)与知识蒸馏

Student and Teacher network指一个较小且较简单的模型&#xff08;学生&#xff09;被训练来模仿一个较大且较复杂的模型&#xff08;教师&#xff09;的行为或预测。教师网络通常是一个经过训练在大型数据集上并在特定任务上表现良好的模型。而学生网络被设计成计算效率高且参…...

FPGA——PLD的区别以及各自的特点

目录 一、概述二、PLD的优点三、PLD的分类1、PROM&#xff08;可编程只读存储器&#xff09;&#xff1a;2、PAL&#xff08;可编程阵列逻辑&#xff09;3、GAL&#xff08;通用阵列逻辑&#xff09;4、CPLD &#xff08;复杂PLD&#xff09;5、FPGA&#xff08;现场可编程门阵…...

八、Kafka时间轮与常见问题

Kafka与时间轮 Kafka中存在大量的延时操作。 1、发送消息-超时重试机制 2、ACKS 用于指定分区中必须要有多少副本收到这条消息&#xff0c;生产者才认为写入成功&#xff08;延时 等&#xff09; Kafka并没有使用JDK自带的Timer或者DelayQueue来实现延迟的功能&#xff0c;而…...

Web端即时通讯技术(SEE,webSocket)

目录 背景简介个人见解被动推送轮询简介实现 长轮询&#xff08;comet&#xff09;简介实现 比较 主动推送长连接&#xff08;SSE&#xff09;简介实现GETPOST 效果 webSocket简介WebSocket的工作原理:WebSocket的主要优点:WebSocket的主要缺点: 实现用法一用法二 **效果** 比较…...

脑电信号处理与特征提取——4.脑电信号的预处理及数据分析要点(彭微微)

目录 四、脑电信号的预处理及数据分析要点 4.1 脑电基础知识回顾 4.2 伪迹 4.3 EEG预处理 4.3.1 滤波 4.3.2 重参考 4.3.3 分段和基线校正 4.3.4 坏段剔除 4.3.5 坏导剔除/插值 4.3.6 独立成分分析ICA 4.4 事件相关电位&#xff08;ERPs&#xff09; 4.4.1 如何获…...

分析npm run serve之后发生了什么?

首先需要明白的是&#xff0c;当你在终端去运行 npm run ****&#xff0c;会是什么过程。 根据上图的一个流程&#xff0c;就可以衍生出很多问题。 1&#xff0c;为什么不直接运行vue-cli-service serve? 因为直接运行 vue-cli-service serve&#xff0c;会报错&#xff0c…...

DAMO-YOLO在Vue前端项目中的实时检测应用

DAMO-YOLO在Vue前端项目中的实时检测应用 1. 引言 想象一下&#xff0c;你正在开发一个智能安防系统&#xff0c;需要在网页上实时检测监控视频中的人员和车辆。传统的方案是将视频流发送到服务器处理&#xff0c;但网络延迟和隐私问题让人头疼。有没有可能在用户的浏览器里直…...

用51单片机+Proteus仿真,从零到一复刻一个数码管电子钟(附完整代码和电路图)

从零构建51单片机数码管电子钟&#xff1a;Proteus仿真与实战全解析 数码管电子钟作为单片机入门经典项目&#xff0c;能系统训练定时器、中断、数码管驱动等核心技能。但很多初学者在独立实现时&#xff0c;常遇到仿真效果不稳定、显示闪烁或计时不准等问题。本文将用保姆级教…...

iptables实战指南:从链表关系到规则配置的完整解析

1. iptables基础概念与核心组件 第一次接触iptables时&#xff0c;我盯着那些复杂的规则配置看了整整一个下午。后来才发现&#xff0c;理解iptables的关键在于掌握它的"四表五链"架构。简单来说&#xff0c;iptables就像是一个多层安检系统&#xff0c;数据包要经过…...

从零开始:使用ecCodes库高效解析GRIB文件

1. 为什么需要ecCodes库处理GRIB文件 第一次接触气象数据时&#xff0c;我被GRIB文件搞得一头雾水。这种二进制格式就像个黑盒子&#xff0c;明明知道里面装着宝贵的温度、气压、风速数据&#xff0c;却不知道怎么取出来。后来发现ecCodes库就像开罐器&#xff0c;能轻松打开这…...

Python偏函数partial的用法小结

functools.partial(func, /, *args, **keywords) 会返回一个新可调用对象&#xff0c;它把原函数 func 的部分位置参数和/或关键字参数“预先绑定”。 这样你就能得到一个“定制版”的函数&#xff0c;后续只需要补齐剩余参数即可调用。返回对象类型是 functools.partial 实例&…...

Python 3.14 JIT为何在ARM64上降频17%?源码级定位_pyltopt_arch.c中2个未对齐的寄存器分配bug(已提交CPython PR#12894)

第一章&#xff1a;Python 3.14 JIT编译器性能降频现象概览Python 3.14 引入的实验性 JIT 编译器&#xff08;基于 Pyjion 与新式 AST 优化管道&#xff09;在部分工作负载下表现出非预期的性能降频现象——即启用 JIT 后&#xff0c;某些计算密集型循环或 I/O 绑定协程的执行耗…...

Qwen3.5-4B-Claude模型Java微服务集成指南:SpringBoot实战案例

Qwen3.5-4B-Claude模型Java微服务集成指南&#xff1a;SpringBoot实战案例 1. 引言&#xff1a;当大模型遇上微服务 最近在开发企业知识管理系统时&#xff0c;我们遇到了一个典型需求&#xff1a;如何让传统Java微服务架构与前沿的大语言模型无缝集成。经过多次尝试&#xf…...

错位排序算法

首先&#xff0c;让我们理解什么是错位排列&#xff1a;错位排列是指在排列中&#xff0c;任何一个元素都不在自己原来的位置上。比如&#xff0c;对于序列 {1,2,3}{1,2,3}&#xff0c;一个错位排列可能是 {3,1,2}{3,1,2}&#xff0c;因为 11 不在位置 11 上&#xff0c;22 不在…...

SGMICRO圣邦微 SGM803B-JXN3G/TR SOT-23-3 监控和复位芯片

特性 适用于MAX803/MAX809/MAX810和ADM803/ADM809/ADM810的卓越升级版 高精度固定检测选项:3V、3.3V和5V 低供电电流:300nA(典型值)上电复位脉冲宽度:150毫秒(最小值) 复位输出选项: 开漏nRESET输出(SGM803B)推挽nRESET输出(SGM809B) . . 推挽复位输出(SGM810B)复位有效电压低至…...

Nunchaku FLUX.1-dev GPU算力优化:TensorRT加速推理实测对比

Nunchaku FLUX.1-dev GPU算力优化&#xff1a;TensorRT加速推理实测对比 如果你正在使用Nunchaku FLUX.1-dev模型生成图片&#xff0c;可能会发现一个问题&#xff1a;生成速度不够快&#xff0c;特别是当你想批量出图或者尝试不同参数时&#xff0c;等待时间有点长。 今天我…...