【linux】free和top显示可用内存不一致|free显示内存90%但是top却看不到谁用

本文解析了free和top显示可用内存不一致的原因,重点介绍了缓冲区与缓存的区别,如何通过cat/proc/meminfo和/proc/sys/vm/drop_caches操作来观察和释放内存,以及何时手动释放内存的注意事项。
摘要由CSDN通过智能技术生成

free和top显示可用内存不一致

free可用内存偏少是top相对free没有统计Slab。这也是导致两者差别的主要原因。

可以使用 cat /proc/meminfo看到内存的更具体的使用情况

以MB为单位显示

cat /proc/meminfo | awk '{print $1,$2/1024" MB"}'|column -t

以GB为单位显示

cat /proc/meminfo | awk '{print $1,$2/(1024*1024)" GB"}'|column -t

free和top显示可用内存不一致_寒夜-CSDN博客_free内存和top不一样

[root@localhost perf5.0]# free -g
              total        used        free      shared  buff/cache   available
Mem:            125         121           0           2           3           0
Swap:             3           3           0

-s 1 每隔一秒输出一次内存使用情况

-hs 1 每隔一秒友好输出一次
 

  • total 内存总量,我的是2G内存
  • used 已经使用的内存
  • free 空闲的内存(对于系统而言,buff/cache属于已经被使用的内存空间)
  • shared 当前已经废弃不用的内存
  • buff/cache 磁盘缓存(当程序使用内存时,会使用这个内存空间)
  • available 可用缓存,理论上等于free + buff/cache
     

磁盘缓存区buff/cache

buffer用来作对io设备写缓存

cache用来作对io设备读缓存

不过现在两者已经写在一起了,统称为程序读写文件的缓存区

实现原理

扇区是设备的最小寻址单元,也叫硬扇区或设备块。

块是操作系统中文件系统的最小寻址单元,也叫“文件块”或"I/O块"

每个块包含一个或多个扇区,但大小不能超过一个页面,一个页可以容纳一个或多个内存中的块。

当一个块被调入内存中时,它要存储在一个缓冲区中,每个缓冲区和一个块对应。

buff/cache 只有块的概念,没有文件的概念,它只是把磁盘上的块直接搬到内存中而不关心块中究竟存放的是什么格式的文件。

Linux的free以及内存释放_黑喵警长的博客-CSDN博客_free释放内存

windows系统的内存是程序运行过程中需要使用才会用到,不用时空闲着。所以当内存使用率过高时,需要检查是否超负载运行。解决方法是停止掉一些进程。

linux系统中,是进程优先使用内存,而不是磁盘。这样会加快读取速度。当有新的进程启动时,再从内存中开辟出一定空间,为新的进程所用。即使进程退出,也不会立刻从内存中清理掉,这样可以加快下次启动进程的速度。所以内存一直是使用率很高的。这是linux系统的独特之处,初使用linux系统的同学需要转换一些思维。不用为linux的内存使用率高而担心。

在图1中,第三行反映出真实内存使用率为12.5%

再介绍一个linux查看内存的命令,free

free命令可以显示当前系统为使用和以使用的内存情况,还可以显示被内存使用的内存缓冲区。[root@vm10-0-0-3 dir]# free

total              used         free        shared    buffers    cached

Mem:      8191064    8063080    127984        748    245932    6791544

-/+ buffers/cache:    1025604    7165460

Swap:            0          0          0

free命令默认以K单位来显示内存使用情况

Mem行显示数据

total:总内存大小

used:已使用内存大小

free:当前空闲内存大小

shared:多个进程共享的内存总额

buffers/cached:缓存内存数据

-/+ buffers/cache行数据显示

这一行的数据代表应用内存使用情况,可理解为真实内存使用情况。如图1中第三行数据。

used:当前(真实)使用内存总数

free:当前(真实)空闲内存总数

-/+ buffers/cache:    1025604    7165460可理解为当前已经使用的内存为1/8,计算公式used/(used+free)。也就是12.6%左右。

Swap代表交换分区,不做过多详解

free常用参数:

free -b      #以Byte为单位显示内存使用情况

free -k      #以KB为单位显示内存使用情况,也是默认参数

free -m      #以MB为单位显示内存使用情况

free -g      #以GB为单位显示内存使用情况

free -o      #不显示应用(真实)内存使用情况列,不推荐

free -s #间隔数字秒数刷新显示内存使用情况

free -t      #显示内存总和列

free -V     #显示当前版本

释放内存 

/proc/sys/vm/drop_caches默认是0

# echo 1 > /proc/sys/vm/drop_caches; free pagecache, use
# echo 2 > /proc/sys/vm/drop_caches; free dentries and inodes
# echo 3 > /proc/sys/vm/drop_caches; free pagecache, dentries and inodes

1:to free pagecache

2:to free dentries and inode

3:to free 1&2

echo 1是释放页缓存,echo 2 是释放slab,而echo 3就是既释放页缓存,又释放slab。

注意:使用之前需要先sync,将缓存刷到磁盘中。

Linux内核默认保持drop_cache的值是0,不建议经常修改它。

写个脚本做这个事情

# cat cleanup_cache.sh 
#!/bin/sh
# drop_caches for every 5 mins

drop_caches() {
    echo "Drop caches."
    sync
    echo 3 > /proc/sys/vm/drop_caches &
    return 0
}

while true; do
    sleep 300
    drop_caches
done

exit 0

/proc/sys/vm/drop_caches 清理缓存 - Hello-World3 - 博客园

手工释放linux内存——/proc/sys/vm/drop_caches - 胡.杰 - 博客园

echo N>/proc/sys/vm/drop_caches清理缓存_邓博学习笔记-CSDN博客

原理

基础知识

buffer和cache在计算机技术中几乎无处不在,这也导致了其在不同语境中代表了不同的东西,下面单独说一下在linux内存管理中,其所代表的含义

  • Cache(Page cache,页面缓存):主要用来作为文件系统上的文件数据的缓存来用,尤其是针对当进程对文件有read/write操作的时候;历史上,buffer被用来当成对io设备写的缓存(不过现在已经几乎不这样干了)
  • Buffer(Buffer cache,缓冲区缓存):主要是针对块设备进行缓存的,比如当我们对一个文件进行写操作的时候,page cache的内容会被改变,而buffer cache则可以用来将page标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。这样,内核在后续执行脏数据的回写(writeback)时,就不用将整个page写回,而只需要写回修改的部分即可。;历史上,cache被用来当作对io设备的读缓存不过现在已经几乎不这样干了)
  • Linux缓存(Cache)回收机制:Linux内核会在内存将要耗尽的时候,触发内存回收的工作,以便释放出内存给急需内存的进程使用。一般情况下,这个操作中主要的内存释放都来自于对buffer/cache的释放。尤其是被使用更多的cache空间。既然它主要用来做缓存,只是在内存够用的时候加快进程对文件的读写速度,那么在内存压力较大的情况下,当然有必要清空释放cache,作为free空间分给相关进程使用。所以一般情况下,我们认为buffer/cache空间可以被释放,这个理解是正确的。但是这种清缓存的工作也并不是没有成本。理解cache是干什么的就可以明白清缓存必须保证cache中的数据跟对应文件中的数据一致,才能对cache进行释放所以伴随着cache清除的行为的,一般都是系统IO飙高。因为内核要对比cache中的数据和对应硬盘文件上的数据是否一致,如果不一致需要写回,之后才能回收。

为了提高磁盘存取效率,Linux做了一些精心的设计,除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换),还采取了两种主要Cache方式:Buffer Cache和Page Cache。前者针对磁盘块的读写,后者针对文件inode的读写。这些Cache有效缩短了 I/O系统调用(比如read,write,getdents)的时间。

那么有人说过段时间,linux会自动释放掉所用的内存。等待一段时间后,我们使用free再来试似乎没有任何变化。(实际情况下,内存的管理还与Swap有关)

那么我能否手动释放掉这些内存呢?回答是可以的!

手动释放缓存 /proc是一个虚拟文件系统,我们把对它的读写操作作为 与kernel实体间进行通信的一种手段。也就是说可以通过修改/proc中的文件,来对当前kernel的行为做出调整。

那么我们可以通过调整/proc/sys/vm/drop_caches来释放内存。

操作如下:

[root@server test]# cat /proc/sys/vm/drop_caches 0

首先,/proc/sys/vm/drop_caches的值,默认为0。

[root@server test]# sync 手动执行sync命令(描述:sync 命令运行 sync 子例程。如果必须停止系统,则运行sync 命令以确保文件系统的完整性。sync 命令将所有未写的系统缓冲区写到磁盘中,包含已修改的 i-node、已延迟的块 I/O 和读写映射文件)

[root@server test]# echo 3 > /proc/sys/vm/drop_caches

[root@server test]# cat /proc/sys/vm/drop_caches 3

将/proc/sys/vm/drop_caches值设为3

[root@server test]# free -m total used free shared buffers cached

Mem: 249 66 182 0 0 11

-/+ buffers/cache: 55 194

Swap: 511 0 511

再来运行free命令,会发现现在的used为66MB,free为182MB,buffers为0MB,cached为11MB。那么有效的释放了buffer和cache。

◎ 有关/proc/sys/vm/drop_caches的用法在下面进行了说明

/proc/sys/vm/drop_caches (since Linux 2.6.16) Writing to this file causes the kernel to drop clean caches, dentries and inodes from memory, causing that memory to become free.
To free pagecache, use echo 1 > /proc/sys/vm/drop_caches; to free dentries and inodes, use echo 2 > /proc/sys/vm/drop_caches; to free pagecache, dentries and inodes, use echo 3 > /proc/sys/vm/drop_caches.
Because this is a non-destructive operation and dirty objects are not freeable, the user should run sync first.

三、我的意见 

……

2、若对于系统内存是否够用的观察,我还是原意去看swap的使用率和si/so两个值的大小;

free小并不是说内存不够用了,应该看的是free的第二行最后一个值: 引用-/+ buffers/cache:

58 191 这才是系统可用的内存大小。 实际项目中告诉我们,如果因为是应用有像内存泄露、溢出的问题,从swap的使用情况是可以比较快速可以判断的,但free上面反而比较难查看。

相反,如果在这个时候,我们告诉用户,修改系统的一个值,“可以”释放内存,free就大了。用户会怎么想?不会觉得操作系统“有问题”吗?

 所以说,我觉得既然核心是可以快速清空buffer或cache,也不难做到(这从上面的操作中可以明显看到),但核心并没有这样做(默认值是0),我们就不应该随便去改变它。 一般情况下,应用在系统上稳定运行了,free值也会保持在一个稳定值的,虽然看上去可能比较小。

当发生内存不足、应用获取不到可用内存、OOM错误等问题时,还是更应该去分析应用方面的原因,如用户量太大导致内存不足、发生应用内存溢出等情况,否则,清空buffer,强制腾出free的大小,可能只是把问题给暂时屏蔽了。

    我觉得,排除内存不足的情况外,除非是在软件开发阶段,需要临时清掉buffer,以判断应用的内存使用情况;或应用已经不再提供支持,即使应用对内存的时候确实有问

题,而且无法避免的情况下,才考虑定时清空buffer。(可惜,这样的应用通常都是运行在老的操作系统版本上,上面的操作也解决不了)。O(∩_∩)O哈哈~

手工释放linux内存——/proc/sys/vm/drop_caches - 胡.杰 - 博客园

meminfo文件详解

meminfo文件详解 - 暗无天日http://blog.lujun9972.win/blog/2018/04/17/meminfo%E6%96%87%E4%BB%B6%E8%AF%A6%E8%A7%A3/

可以看出,这里的内核信息特别多,有些含义很难理解。

下面就来尝试解释一下这些行的意义:

MemTotal

总共安装的物理内存容量

MemFree

当前空闲的内存量

MemAvailable

Buffers / Cached

buffers + cached的值就是可以使用的磁盘告诉缓存的大小。

buffers + cached = Active(file) + Inactive(file) + Shmem

SwapCached

记录在交换缓存上的内容容量。

所谓交换缓存是指,在换入某个内存页之后,物理磁盘上的交换空间依然保留同样的数据,这样的内存页会记录在"交换缓存"的列表上。 这样的好处在于,当需要再次换出记录在交换缓存中的的内存页时,可以直接使用交换分区中保存的内容,而无需将内存再次写入交换空间。

当该交换空间上的其他数据被换出,或是换入内存中的数据被改写,则交换缓存上的记录会被清空。

Active

等于Active(anon) + Active(file)的和

Inactive

等于Inactive(anon) + Inactive(file)的和

Active(anon) / Inactive(anon) / Active(file) / Inactive(file)

括号中为anon的内存为匿名内存,括号中为file的内存为file-backed内存,这两个内存的区别在于,物理内存的内容是否与物理磁盘上的文件相关联。

其中,匿名内存就是进程中堆上分配的内存,是用malloc分配的内存。

而file-backed内存为磁盘高速缓存的内存空间和“文件映射(将物理磁盘上的文件内容与用户进程的逻辑地址直接关联)”的内存空间,其中的内容与物理磁盘上的文件相对应。

而Active和Inactive的区别在于内存空间中是否包含最近被使用过的数据。

当物理内存不足,不得不释放正在使用的内存空间时,会优先释放Inactive的内存空间。

Linux内核中使用4类LRU表来分别记录对应的这4类内存页,内存页一般以4K为一页。

Unevictable

有些内存页是不能被释放的,这些内存页不能放在LRU表中,而是记录到Unevictable标中

Mlocked

SwapTotal

交换空间的总大小

SwapFree

交换空间的剩余容量

Dirty

脏数据,在磁盘缓冲区中尚未写入物理磁盘的内存大小

Writeback

AnonPages

Linux内核中存在一个rmap(reverse mapping)机制,负责管理匿名内存中每一个物理内存页映射到哪个进程的哪个逻辑地址这样的信息。 这个rmap中记录的内存页总和就是AnonPages的值。

Mapped

Shmem

tmpfs所使用的内存.

tmpfs即利用物理内存来提供RAM磁盘的功能。在tmpfs上保存文件时,文件系统会暂时将它们保存到磁盘高速缓存上,因此它是属于磁盘高速缓存对应的"buffers+cached"一类。 但是由于磁盘上并没有与之对应的内容,因此它并记录在File-backed内存对应的LRU列表上,而是记录在匿名内存的LRU表上。 这就是 buffers + cached = Active(file) + Inactive(file) + Shmem 公式的由来

Slab

由"Slab分配器"分配的总量。Slab分配器针对一些经常分配并释放的对象(如进程描述符)统计各种数据类型的汇总信息,然后为每种数据类型创建多个由多个内存页组成的Slab(这些Slab组成一个Slab列表)。 再在Slab内部划分成一个个相应数据类型的对象。

当内核要使用某种类型的数据结构时,就从对应的slab列表中分配一个对象出去,而当要释放时,将其重新保存在Slab列表中,从而避免内存碎片。

当可供使用的对象不足时,会使用空闲的内存页来创建并添加新的Slab到对应对象的Slab列表中。 相反,若Slab中所有对象都被内核回收,即所有对象都未使用时,根据需要也可以回收Slab,释放成空闲内存。

从 /proc/slabinfo 中我们可以查看每个Slab的信息:

sudo cat /proc/slabinfo |head
slabinfo - version: 2.1
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
nf_conntrack          27     72    320   12    1 : tunables    0    0    0 : slabdata      6      6      0
ovl_inode             46     46    688   23    4 : tunables    0    0    0 : slabdata      2      2      0
fuse_request          40     40    400   20    2 : tunables    0    0    0 : slabdata      2      2      0
fuse_inode            19     19    832   19    4 : tunables    0    0    0 : slabdata      1      1      0
xfs_dqtrx              0      0    528   15    2 : tunables    0    0    0 : slabdata      0      0      0
xfs_rui_item           0      0    672   12    2 : tunables    0    0    0 : slabdata      0      0      0
xfs_rud_item           0      0    152   26    1 : tunables    0    0    0 : slabdata      0      0      0
xfs_ili             4486   4488    168   24    1 : tunables    0    0    0 : slabdata    187    187      0

其中:

name

对象名称

active_objs

处于活跃状态的对象个数

num_objs

slab列表中的总对象数量

objperslab

一个slab中包含的对象个数

pageperslab

每个slab占用的内存页数

num_slabs

slab列表中slab的个数

active_slabs

处于活跃状态的slab个数

SReclaimable

不存在活跃对象,可以回收的Slab容量

SUnreclaim

对象处于活跃状态,不能被回收的Slab容量

KernelStack

KernelStack是内核代码使用的堆栈区域。

由于Linux内核中用户进程在运行过程中需要不断切换,因此内核需要为每个用户进程都设置各自的堆栈区域。 因此,每启动一个新进程,KernelStack的值都会增加。

PageTables

PageTables就是页表,用于存储各个用户进程的逻辑地址和物理地址的变换关系,它本身也是一个内存区域。

NFS_Unstable

Bounce

WritebackTmp

CommitLimit

Committed_AS

VmallocTotal

Linux使用内存时,除了使用Slab中配置的对象外,还能直接将空闲内存页映射到逻辑地址上。

这个容量指的是,理论上内核内部可以用来映射的逻辑地址的范围。这个值非常大,但并非实际使用的物理内存

VmallocUsed

实际上,Linux将空闲内存页映射到逻辑地址上的容量。

值得说明的是,这个容量除了物理内存上所作的映射外,也包括诸如视频卡这样的外部设备内存所作的映射,这类映射叫做"ioremap"

我们可以通过 /proc/vmallocainfo 查看VmallocUsed中包含内存区域的详情

cat /proc/vmallocinfo |head
0x000000008088114a-0x000000001aecb69b    8192 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6bd000 ioremap
0x000000001aecb69b-0x0000000086f9fed7    8192 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6e4000 ioremap
0x0000000086f9fed7-0x000000006fbc598c    8192 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6e2000 ioremap
0x000000006fbc598c-0x00000000636e4cf9   12288 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6e2000 ioremap
0x00000000636e4cf9-0x000000005464ab58    8192 hpet_enable+0x34/0x2c1 phys=0x00000000fed00000 ioremap
0x000000005464ab58-0x00000000396cc741   12288 alloc_large_system_hash+0x194/0x257 pages=2 vmalloc N0=2
0x00000000396cc741-0x0000000038ec28d8    8192 bpf_prog_alloc+0x40/0xb0 pages=1 vmalloc N0=1
0x0000000038ec28d8-0x000000002f686ade   65536 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6bd000 ioremap
0x000000002f686ade-0x00000000fee69f16 4198400 alloc_large_system_hash+0x194/0x257 pages=1024 vmalloc vpages N0=1024
0x00000000fee69f16-0x00000000362aad15 2101248 alloc_large_system_hash+0x194/0x257 pages=512 vmalloc N0=512

其中

  • 第一列为逻辑地址的范围
  • 第二列为容量,以字节为单位
  • 最后一列若为ioremap,说明该映射为ioremap

所以要计算除ioremap外物理内存的映射量,可以这么计算

sudo cat /proc/vmallocinfo |grep -v "ioremap" |awk '{total=total+$2};END{print total}'
107110400

VmallocChunk

HardwareCorrupted

AnonHugePages

ShmemHugePages

ShmemPmdMapped

HugePages_Total

HugePages_Free

HugePages_Rsvd

HugePages_Surp

Hugepagesize

DirectMap4k

DirectMap2M

active_anon/inactive_anon

使用内存区别

  • rss

属于进程的数据,如 Stacks、Heaps 等。可以被进一步分解为

  • 活动内存(active_anon)
  • 非活动内存(inactive_anon)

必要时,非活动内存可以被交换到磁盘

  • cache

缓存存储器存储当前保存在内存中的磁盘数据。可以进一步分解为

  • 活动内存(active_file)
  • 非活动内存(inactive_file)

必要时,首先回收非活动内存

  • swap 使用量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值