写在前面
本文看下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分配器是干嘛用的?
管理小内存。