Linux性能优化之内存管理基础知识

写在前面

本文看下Linux内存管理相关基础内容。

1:linux是如何管理的内存的?

我们平时所说的内存多大的内存,指的是物理内存,物理上就是一个内存条:

物理内存,也叫主存,现在的主存一般是动态随机访问内存,即DRAM。但物理内存只有内核才有权限访问。为了解决这个问题,定义了虚拟内存来给进程使用,虚拟内存分为用户空间和内核空间两部分,进程处于用户态时可以访问用户空间,处于内核态时可以访问内核空间。虚拟空间的大小由字长(一次能处理的数据量)来决定,常见的32和64位操作系统如下:

前面说了,进程只能访问虚拟内存,但是最终还是要访问到物理内存的,因此,在虚拟内存和物理内存之间需要增加一层映射,这个映射叫做页表,而页表是存储在CPU的内存管理单元MMU中的,如下图:

MMU管理内存的单位是页,页的大小是4k,所以对于4G内存,就会由100w个条目来维护映射关系,显然数量还是蛮大的,为了解决这个条目过多的问题,引入了多级页表和大页,多级页表是将内存分成块来处理,块还有下级块,构成一种树形的结构,并且只有真正分配内存的区域才会真的定义块信息,这样就解决了普通页表条目过多的问题。大页就是页更大,一般是2M和1G,一般用在会占用大内存的程序,如Oracle,dpdk等。

通过映射进程就可以使用到真正的物理内存了。

虚拟内存空间,还可以再进行细分,其中主要是对于用户空间,如下图:

每个部分存储了不同的内容,如下,了解即可:

复制代码
只读段,包括代码和常量等。
数据段,包括全局变量等。
堆,包括动态分配的内存,从低地址开始向上增长。需要动态申请。
文件映射段,包括动态库、共享内存等,从高地址开始向下增长。需要动态申请。
栈,包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是 8 MB。

接着我们来看下内存的申请和回收。

2:应用程序如何申请和回收内存?

内存的申请通过c语言的malloc()函数完成,对应到系统调用,有brk()和mmap()两种方式,其中前者用于申请小于128k的内存,后者用于申请大于128k的内存。释放的话执行free(),unmap()即可。

系统的物理内存是有限的,肯定不能让进程无限制的申请,所以当内存紧张时操作系统肯定要做些什么的,主要如下几件事:

复制代码
1:根据一定的算法回收内存,如LRU
2:使用swap回收不常使用内存
3:使用OOM机制,杀死占用了大量内存的进程,弃车报帅。

其中2,swap就是交换分区,是一种把磁盘当作内存来使用的机制,其中将内存中的数据写到磁盘中叫做换出,反之将磁盘中的数据写回到内存中叫做换入。看起来,swap将系统的内存变大了,但其实这只是一种在内存紧张时才会启用的紧急机制,因为磁盘的访问速度远低于内存,所以是会带来比较严重的性能问题。

对于3,linux定义了oom_score来标记一个进程使用内存的量,值越大表示使用内存越多,内存紧张时越容易被OOM KILL,如下参看:

复制代码
root@hellohp:/proc# cat /proc/582988/oom_score
65

即通过proc文件系统来查看内核的信息。命令中间的数字是进程号。

另外,我们也可以通过oom_adj来调节oom_score的值,数值范围-17,15数值越小,oom_score越低,越不容易被OOM,-17代表不允许OOM KILL,同样可以通proc文件系统查看进程oom_adj的值:

复制代码
root@hellohp:/proc# cat /proc/582988/oom_adj
-16

3:如何查看内存使用情况?

free命令查看系统的内存使用情况:

复制代码
root@hellohp:/proc# free
               total        used        free      shared  buff/cache   available
Mem:         3961340     1393332      813172        1760     2054468     2568008
Swap:              0           0           0

第一行是物理内存的使用信息,第二行是交换内存的使用信息,每一列的含义如下:

复制代码
total:总的内存大小
used:已经使用的内存大小,包含共享
free:未使用内存,不包含可回收
shared:共享内存
buff/cache:缓存,缓冲区大小
available:未使用和可回收

top查看进程内存信息:

复制代码
root@hellohp:/proc# free
               total        used        free      shared  buff/cache   available
Mem:         3961340     1393332      813172        1760     2054468     2568008
Swap:              0           0           0
root@hellohp:/proc# top
top - 09:34:28 up 7 days,  7:48,  5 users,  load average: 0.42, 0.34, 0.30
Tasks: 255 total,   1 running, 254 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.7 us,  2.4 sy,  0.0 ni, 94.6 id,  0.2 wa,  0.0 hi,  0.2 si,  0.0 st
MiB Mem :   3868.5 total,    800.5 free,   1353.7 used,   2006.9 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   2514.8 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 582988 root      20   0 1622064 377028 104812 S   9.3   9.5 202:51.60 kubelite
 ...

相关列含义:

复制代码
VIRT:虚拟内存大小,申请过的就算,就算没有真正分配也算
RES:常驻内存大小,实际使用的物理内存大小,但不包括swap和共享内存
SHR:共享内存的大小
%MEM:使用物理内存占总内存的百分比

写在后面

参考文章列表

多知道一点

TLB是什么?

MMU的高速缓存。

什么是缺页异常?

当通过页表访问内存时,不存在对应的物理内存信息时,抛出的异常就是缺页异常,发生该异常后会申请物理内存,并更新页表信息。

什么是伙伴系统?

伙伴系统是用来管理内存分配工作的一个系统。当执行malloc时就需要依赖于伙伴系统来完整真正的内存分配。

slab分配器是干嘛用的?

管理小内存。

相关推荐
薛定谔的悦3 小时前
储能 EMS 的功率策略:从一块电表到一次逆流的 200 毫秒
大数据·linux·能源·储能·bms
新时代牛马6 小时前
Linux 内核入门地图:架构、源码目录与五大子系统
linux·运维·架构
Julien20046 小时前
控制 SELinux 文件上下文
linux·运维·服务器
EXI-小洲6 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
sulikey7 小时前
Linux Core Dump 完全指南:从原理到实战的崩溃调试手册。什么是core dump?程序报错core dumped怎么办?
linux·服务器·操作系统·调试·coredump
2601_961901708 小时前
SpringBoot使用Nacos进行application.yml配置管理
java·spring boot·spring
何以解忧,唯有..8 小时前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
QQ_21696290969 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端
MayZork9 小时前
Windows 与 Linux 下 vcpkg 的安装部署指南
linux·运维·windows
前端 贾公子10 小时前
第09章:上下文与记忆 (2)
java·服务器·前端