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

管理小内存。

相关推荐
刘~浪地球2 小时前
数据库性能优化实战
数据库·性能优化
杰 .2 小时前
闲暇时刻对LinuxOS的部分理解(一)
linux·服务器
范什么特西2 小时前
idea创建一个普通的Maven项目运行javaweb
java·maven·intellij-idea
摩斯电码2 小时前
深入 perf 第二版(二):用原始事件编号解锁 CPU 的隐藏指标
linux·性能优化
好家伙VCC2 小时前
# 发散创新:用 Rust实现高性能物理引擎的底层架构设计与实战在游戏开发、虚拟仿真和机器人控
java·开发语言·python·rust·机器人
六道对穿肠2 小时前
Java 直连 USB 打印机实战:从 JNI 崩溃到「拷贝即用」的架构演进
java
代码中介商2 小时前
Linux 基础命令完全指南:从文件操作到进程管理
linux·运维·服务器
user_admin_god2 小时前
OpenCode入门到入坑
java·人工智能·spring boot·语言模型
Maiko Star2 小时前
Claude Code安装教程
java·chatgpt·claude code