Linux中free命令各字段详解以及内存和cache相关知识整理
今天在跑⼀个python排序程序的时候,想通过top命令检查程序消耗内存的变化。很奇怪,检测到的内存使⽤⽐预期的要⾼不少。刚好借这个机会整理下Linux中内存管理的⼀些知识。
⽂章⽬录
free命令
通过free命令可以查看当前系统的内存使⽤情况,参数-h可以将单位⾃动转换的⽐较友好
[root@testmachine tools]# free -h
total used free shared buff/cache available
Mem: 3.7G 1.8G 163M 9.1M 1.8G 1.6G
Swap: 2.0G 925M 1.1G
先看第⼀⾏Mem部分的内容
total - 物理内存的总和
used - 已经被应⽤程序使⽤的内存⼤⼩
free - 完全空闲的内存⼤⼩
shared - 被共享的内存
buff/cache - 被当作缓存使⽤的内存⼤⼩
available - 可以被新的应⽤程序使⽤的内存⼤⼩
这⾥可能有朋友会有疑问,你电脑3.7G的内存怎么只剩下了163M,是不是系统出了问题?或者为什么只有163M内存可⽤,但新的程序却⼜可以使⽤1.6G的内存?这些疑问我们下⾯都会解答。
再来看第⼆⾏Swap,交换区
total - 可被⽤作swap的硬盘总⼤⼩
used - 被使⽤的swap⼤⼩
free - 可被使⽤的swap⼤⼩
⾄于什么是交换区,有什么⽤,后⾯我们也会单独说。
toy什么意思内存映射与页
先来说说内存使⽤的基本逻辑。
每个进程都有⾃⼰的独⽴寻址空间,也就是说某进程创建的变量不会被另⼀个进程访问到。进程能寻址的地址叫做虚拟内存,针对32位寻址的机器,每个进程有2^32个寻址地址,也就是4GB,⽽64位寻址的机器,理论上有2^64个寻址地址。但是受限于主板和地址线个数,⽬前内存条基本都是16GB的(2020年7⽉),物理内存条对应的是物理内存。
那么问题就来了,虚拟内存和物理内存之间⼤⼩明显不匹配,物理内存似乎完全不够⽤,这是怎么回事?
解答这个问题前,先来聊⼀聊页(Page)。
计算机会对虚拟内存和物理内存按照最⼩单位4KB进⾏处理,虚拟内存中的4KB称为页(Page),物理内存中的4KB称为页帧(Page Frame),页和页帧之间的对应关系称为内存映射。所有的进程共享同⼀物理内存,每个进程也只会把⽬前需要的虚拟内存地址映射到物理内存中。
进程去页中查询所需要的数据,⽽真正的数据都在页帧中,所以还需要⼀个页表(Page Table)去管理这种对应关系以便进程去查。页表的每⼀条记录分为两部分,第⼀部分记录此页是否在物理内存
中,第⼆部分记录物理内存页帧的地址(如果存在的话)。
当进程想要访问某个虚拟地址,但是没有在页表中查到物理内存的地址,说明数据还没有读到内存中,这叫做缺页异常(Page Fault)。此时进程会将数据从硬盘读到物理内存中,并更新页表。假如从硬盘读⼊内存的时候,内存中的页帧都被⽤了,就会⼀个使⽤较少的页帧进⾏覆盖。
所以就可以回答上⾯的问题了。虽然每个进程有⾃⼰独⽴的虚拟内存地址,但是只是把需要⽤到的部分映射到物理内存,有了新的需求再去映射新的。所以虽然所有进程都共享物理内存,也会彼此独⽴。
那么内存中使⽤完毕的页帧会被马上收回吗?答案是并不会。这也是为什么好像机器上没有运⾏啥程序但是还是显⽰free的内存很少的原因,因为⼤量的内存都是之前使⽤过,但是并没有释放的部分,这就是buffer和cache。
buffer和cache
先来看下⾯这个现象。我这⾥有⼀个1.1GB⼤⼩的⽂件,同样是读取整个⽂件,第⼀次读取花了1.3秒,⽽以后再读取只需要0.2秒
[root@testmachine linkedlist]# ll -
-rw-rw-r-- 1 fuhx fuhx 1.1G Jul 17 17:
[root@testmachine linkedlist]# free -h
total used free shared buff/cache available
Mem: 3.7G 1.7G 1.8G 17M 227M 1.7G
Swap: 2.0G 922M 1.1G
[root@testmachine linkedlist]# time > /dev/null
real 0m1.317s
user 0m0.006s
sys 0m1.306s
[root@testmachine linkedlist]# time > /dev/null
卫生间装修价格real 0m0.236s
user 0m0.006s
sys 0m0.229s
[root@testmachine linkedlist]# time > /dev/null
real 0m0.211s
user 0m0.013s
sys 0m0.198s
[root@testmachine linkedlist]# free -h
total used free shared buff/cache available
Mem: 3.7G 1.7G 729M 17M 1.3G 1.6G
Swap: 2.0G 922M 1.1G
同样值得注意的是,读取⽂件前后,free部分的内存下降了约1GB,⽽buff/cache部分的内存上升了约1GB。
这说明整个⽂件都被缓存在了内存中,除了第⼀次调⽤需要从硬盘读到内存,以后每次都是直接从内存读取,所以会快很多
buffer和cache⼀个是缓冲区⼀个是缓存,不过这⾥都可以理解成内存和硬盘之间交互的⼀个中间层。
page cache
针对⽤页来管理的内存,其缓存被称为page cache。其主要是在进程对⽂件进⾏读写操作时发挥作⽤。
⽤户读写与page cache
读⽂件时,⽤户发起read操作,进程查页表,如果有映射到页帧,则直接返回页帧中返回的内容,如果没有匹配的页帧,则触发缺页异常,从硬盘读取数据到页帧进⾏缓存,read操作完成。
写⽂件时,⽤户发起write操作,进程查页表,如果有映射到页帧,直接写到页帧中,此时的页被称为脏页(Dirty Page),如果没有匹配的页帧,则创建页帧写⼊数据。⽤户write操作完成。此后操作系统有两种⽅式将脏页回写到硬盘,⽤户⼿动调⽤fsync()或者由pdflush进程定时将脏页写回。
不管是读还是写,有对应的cache称为命中,命中率是判断某进程缓存好换的关键指标。
这也就回答了上⾯的疑问,电脑3.7G的内存怎么只剩下了163M,是不是系统出了问题?并不是电脑出了问题,⽽是Linux的内存管理机制就是这样,尽可能地对硬盘数据进⾏缓存,以加快读写速率。这⼀点跟Windows不⼀样。
当有新的程序要申请内存时,这些被缓存占⽤的内存会被释放,这就是为什么available的内存会将缓存也算进去。
当然,虽然不建议,但是如果想⼿动清除cache也是可以的。
感恩节文案幼儿园⼿动清理cache
通过修改内核参数可以达到删除cache的⽬的
[root@testmachine tools]# free -h
total used free shared buff/cache available
Mem: 3.7G 1.8G 163M 9.1M 1.8G 1.6G
Swap: 2.0G 925M 1.1G
[root@testmachine tools]# echo 3 > /proc/sys/vm/drop_caches
[root@testmachine tools]# free -h
total used free shared buff/cache available
Mem: 3.7G 1.7G 1.7G 9.1M 221M 1.7G
Swap: 2.0G 925M 1.1G
Linux中⼀切皆⽂件,内核的各种设置也以⽂件形式提供操作API,这就是/proc/sys/⽬录。临时的修改只需要将值echo到⽂件即可,因为是直接作⽤于内存所以马上⽣效,但是机器重启就会消失。永久⽣效需要在/f或者是/etc/sysctl.f中将⽬录换成点号进⾏赋值。例如echo 1 > proc/sys/net/ipv4/ip_forward就写成net.ipv4.ip_forward=1然后跑命令sysctl -p从⽂件⽣效
关于内核参数调优,可以参考,和内存相关的都在/proc/sys/vm/⽬录下
⾸先,这种清理也并不是没有成本的。前⾯说过⽤户执⾏写操作会产⽣脏页,如果存在脏页,系统要先写回到硬盘才能回收内存。所以清除缓存通常伴随着⾼I/O。
同时可以发现cache并不会完全清除,这是因为有些cache不能被系统回收,例如tmpfs,进程间的通讯⽤的共享内存等等,更多细节可以参考。
再次强调,Linux的缓存是不需要⼿动去清理的。
内存使⽤增多排查步骤
如果发现内存在⼀点点被蚕⾷,可以按照推荐的步骤来排查
1. 通过 free,发现⼤部分内存都被缓存占⽤后
2. 可以使⽤ vmstat 或者 sar观察⼀下缓存的变化趋势,确认缓存的使⽤是否还在继续增⼤。
3. 如果继续增⼤,则说明导致缓存升⾼的进程还在运⾏,那你就能⽤缓存 / 缓冲区分析⼯具(⽐如 cachetop、slabtop 等),分析这
些缓存到底被哪⾥占⽤。
4. 排除缓存 / 缓冲区后,你可以继续⽤ pidstat 或者 top,定位占⽤内存最多的进程。
5. 出进程后,再通过进程内存空间⼯具(⽐如 pmap),分析进程地址空间中内存的使⽤情况就可
以了。
6. 通过 vmstat 或者 sar 发现内存在不断增长后,可以分析中是否存在内存泄漏的问题。⽐如你可以使⽤内存分配分析⼯具 memleak
,检查是否存在内存泄漏。如果存在内存泄漏问题,memleak 会为你输出内存泄漏的进程以及调⽤堆栈内存泄漏:memory leak,内存使⽤完毕没有回收,导致该区域永远⽆法被后⾯的进程使⽤的现象
swap
justinbieber下⾯来说说swap,也就是交换区。
所谓的swap,就是将⼀部分硬盘当作内存来使⽤。内存中不常⽤的⼀部分会被交换到swap,下次再使⽤的时候再交换回内存,分别叫做换出和换⼊。
既可以在分区的时候就设定⼀块盘做为swap,例如我电脑这样
[root@testmachine shm]# fdisk -l
Disk /dev/sda: 53.7 GB, 53687091200 bytes, 104857600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000c328c
Device Boot Start End Blocks Id System
/dev/sda1 * 2048 2099199 1048576 83 Linux牛顿三定律
/dev/sda2 2099200 41943039 19921920 8e Linux LVM
/dev/sda3 41943040 104857599 31457280 83 Linux
Disk /dev/mapper/centos-root: 49.4 GB, 49387929600 bytes, 96460800 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/mapper/centos-swap: 2147 MB, 2147483648 bytes, 4194304 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes工科类专业
或者像下⾯这样创建⼀个⽂件做为swap。
⽂件作为swap分区
1.创建要作为swap分区的⽂件:增加1GB⼤⼩的交换分区,则命令写法如下,其中的count等于想要的块的数量(bs*count=⽂件⼤⼩)。dd if=/dev/zero of=/root/swapfile bs=1M count=1024
2.格式化为交换分区⽂件:
mkswap /root/swapfile #建⽴swap的⽂件系统
3.启⽤交换分区⽂件:
swapon /root/swapfile #启⽤swap⽂件
4.使系统开机时⾃启⽤,在⽂件/etc/fstab中添加⼀⾏:
/root/swapfile swap swap defaults 0 0
swappiness
有⼀个内核参数如下
[root@testmachine shm]# cat /proc/sys/vm/swappiness
30
这是⼀个介于0-100的配置项,⽤来表⽰系统进⾏内存回收时候的偏好。数值越⼤,在内存回收时越偏好使⽤swap,也就是将⼀些不常⽤的页换出;数值约⼩,在内存回收时越拒绝使⽤swap,也就是更倾向将缓存直接释放或者脏页写回硬盘再释放。
通常为了提升性能,建议将这个值设置为0。
内存管理优化
在中还推荐了很多内存优化的⼯具,像cachetop,vmstat等,以及⼀些优化思路。做为补充内容放在这⾥了。
我是T型⼈⼩付,⼀位坚持终⾝学习的互联⽹从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。
发布评论