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分配器是干嘛用的?

管理小内存。

相关推荐
A小辣椒17 小时前
TShark:Wireshark CLI 功能
linux
唐青枫20 小时前
Java JDBC 实战指南:从 Connection 到事务和连接池
java
一个做软件开发的牛马21 小时前
MyBatis-Plus 从零实战:完整搭建可运行 Demo,BaseMapper 零 SQL、Wrapper 条件构造、分页插件与代码生成器详解
java·后端
用户37215742613521 小时前
Java 处理 PDF 图片:提取 PDF 中的图片,并压缩 PDF 图片体积
java
A小辣椒21 小时前
TShark:基础知识
linux
用户37215742613521 小时前
Java 打印 Word 文档:从基础打印到高级设置
java
AlfredZhao1 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
用户3521802454752 天前
当 Prompt 学会"热更新":Spring Boot × Nacos3 AI 实战
java·spring boot·ai编程
jump_jump2 天前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi