linux查看内存空间分配情况,也看linux内存去哪儿了

本文详细分析了Linux系统中内存的使用情况,包括RSS(Resident Set Size)、Slab内存和PageTables的消耗。通过实例计算,展示了如何通过/proc目录下的文件来监测内存分配,并解释了为何RSS、Slab和PageTables之和可能大于实际使用内存。此外,讨论了在特定场景如Oracle数据库中,SGA预先分配的内存如何影响内存统计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前两天一台128G内存的oracle主机发生故障触发kdump,最终由于var目录空间不足,导致kdump生成不完全。结合之前redhat给出的建议,crash设置的空间最好大于memory 空间。对此我们做了一个简单的计算,认为kdump主机生成的是运行在内存里的信息 ,虽然主机有128G的内存,不过通过top查看并计算后发现我实际上只使用7G多的大小,而使用free -m查看时已经使用了80G左右的内存 。站在DBA的角度看的话,这部分内存提前分配给了sga ,貌似也可以讲通。记得之前看过taobao褚霸写的一篇分析。这里再结合该文章算算。

通过褚霸的Linux Used内存到底哪里去了?我们已经了解到内存主要消耗在三个方面:1. 进程消耗。 2. slab消耗 3.pagetable消耗。

由于不便于直接在现网oracle主机上进行操作,这里就以本blog的云主机为例进行测试。

一、查看已用内存总量

[root@91it ~]# free -m

total used free shared buffers cached

Mem: 996 908 88 0 174 283

-/+ buffers/cache: 450 546

Swap: 0 0 0

关于已用内存和可用内存这已经是一个老生长谈的问题了。这里看到的信息如下:

1、总内存996M ,已用内存908M

2、由于buffers + cached内存实际上也是可用内存,该内存也可以通过echo 3 > /proc/sys/vm/drop_caches 回收pagechae、dentries and inodes ,所以实际上已经使用的内存是450M 。

注:

1、关于内存的计算方法就不上图了,这点可以参考:http://www.redbooks.ibm.com/redpapers/pdfs/redp4285.pdf

2、linux内存强制回收的方法具体可以参考:linux 下 强制回收内存 。

即然实际使用了450M内存,那这450M内存是如何分配的呢?

二、RSS内存(Resident size)

ps下命令下的RSS内存、top工具下的RES内存都是指的这一块内存。resident set size 也就是每个进程用了具体的多少页的内存。由于linux系统采用的是虚拟内存,进程的代码,库,堆和栈使用的内存都会消耗内存,但是申请出来的内存,只要没真正touch过,是不算的,因为没有真正为之分配物理页面,说白了也就是真正具有“数据页的物理内存”。我这里使用的是一段从python psutil 模块里演化出的一段代码进行计算的:

[root@91it ~]# cat vms.py

#!/usr/bin/python

import os

def get_vms(pid):

with open("/proc/%s/statm" % pid, "rb") as f:

vms = f.readline().split()[1]

return int(vms)

pids = [int(x) for x in os.listdir(b'/proc') if x.isdigit()]

vmss = [get_vms(pid) for pid in pids]

print sum(vmss) * 4

[root@91it ~]# python vms.py

386528

注:

1、/proc/PID/statm 第二列是RSS内存使用page页的多少,而在linux下默认使用的page页大小是4KB 。所以我上面计算求和后,最后乘以4 ,而我最终计算出的结果就是386528KB 。

2、这里也可以通过/proc/PID/status里的vmRss项进行求和,因为该项直接给出的是KB值。

[root@91it ~]# cat /proc/998/status

Name: mingetty

State: S (sleeping)

Tgid: 998

Pid: 998

PPid: 1

TracerPid: 0

Uid: 0 0 0 0

Gid: 0 0 0 0

Utrace: 0

FDSize: 64

Groups:

VmPeak: 4068 kB

VmSize: 4064 kB

VmLck: 0 kB

VmHWM: 556 kB

VmRSS: 76 kB

………………………………

当然也可以使用shell 进行计算:

$ cat RSS.sh

#/bin/bash

for PROC in `ls /proc/|grep "^[0-9]"`

do

if [ -f /proc/$PROC/statm ]; then

TEP=`cat /proc/$PROC/statm | awk '{print ($2)}'`

RSS=`expr $RSS + $TEP`

fi

done

RSS=`expr $RSS \* 4`

echo $RSS"KB"

rss内存部分,具体可以查看man proc手册或kernl 页的介绍 ,以下是man proc 里的部分提取:

/proc/[pid]/statm

Provides information about memory usage, measured in pages. The

columns are:

size total program size

(same as VmSize in /proc/[pid]/status)

resident resident set size

(same as VmRSS in /proc/[pid]/status)

share shared pages (from shared mappings)

text text (code)

lib library (unused in Linux 2.6)

data data + stack

dt dirty pages (unused in Linux 2.6)

二、slab内存

slab内存的作用是内核为了高性能每个需要重复使用的对象都会有个池,这个slab池会cache大量常用的对象,所以会消耗大量的内存。具体可以运行slabtop命令查看。

e560235816b686931bf301bec7b7df7e.png

slab内存的消耗我们可以通过/proc/slabinfo文件算出,具脚本为:

# echo `cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'` MB

74.7215 MB

三、PageTables内存

这部分内存我并没有细研究,这里就直接拉taobao上各位大牛的说法用吧:“struct page也有一定的大小(每个页一个,64bytes),如果是2.6.32的话,每个页还有一个page_cgroup(32bytes),也就是说内存大小的2.3%(96/4096)会被内核固定使用 。struct page是系统boot的时候就会根据内存大小算出来分配出去的,18内核是1.56%左右,32内核由于cgroup的原因会在2.3% 。”

而具体消耗可以通过/proc/meminfo里的pagetables项获取,脚本如下:

# echo `grep PageTables /proc/meminfo | awk '{print $2}'` KB

4476 KB

系统的硬开销占比并不多。

四、算算总帐

三者加起来发现要大于450M 。这里我们便于查看,再跑下脚本:

$ cat cm.sh

#/bin/bash

for PROC in `ls /proc/|grep "^[0-9]"`

do

if [ -f /proc/$PROC/statm ]; then

TEP=`cat /proc/$PROC/statm | awk '{print ($2)}'`

RSS=`expr $RSS + $TEP`

fi

done

RSS=`expr $RSS \* 4`

PageTable=`grep PageTables /proc/meminfo | awk '{print $2}'`

SlabInfo=`cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'`

echo $RSS"KB", $PageTable"KB", $SlabInfo"MB"

printf "rss+pagetable+slabinfo=%sMB\n" `echo $RSS/1024 + $PageTable/1024 + $SlabInfo|bc`

free -m

$ ./cm.sh

382048KB, 4528KB, 74.8561MB

rss+pagetable+slabinfo=451.8561MB

total used free shared buffers cached

Mem: 996 842 154 0 106 376

-/+ buffers/cache: 359 637

Swap: 0 0 0

由于上面演示时,我强制回收过内存。目前实际已用内存为359M ,而我们上面三者之和是451M,比实际使用的大了100M左右。

多出的这部分内存是我们在计算rss内存时算重复了。因为rss内存包括我们使用的各种库和so等共享的模块。具体可以使用pmap指令查看详细的每个进程调用的lib库及已用内存值。这里以最简单的bash进程为例。

[root@91it ~]# pmap `pgrep bash`

1464: -bash

0000000000400000 848K r-x-- /bin/bash

00000000006d3000 40K rw--- /bin/bash

00000000006dd000 20K rw--- [ anon ]

00000000008dc000 36K rw--- /bin/bash

00000000011a4000 396K rw--- [ anon ]

0000003ef9800000 128K r-x-- /lib64/ld-2.12.so

0000003ef9a1f000 4K r---- /lib64/ld-2.12.so

0000003ef9a20000 4K rw--- /lib64/ld-2.12.so

0000003ef9a21000 4K rw--- [ anon ]

0000003ef9c00000 1576K r-x-- /lib64/libc-2.12.so

0000003ef9d8a000 2048K ----- /lib64/libc-2.12.so

0000003ef9f8a000 16K r---- /lib64/libc-2.12.so

0000003ef9f8e000 4K rw--- /lib64/libc-2.12.so

0000003ef9f8f000 20K rw--- [ anon ]

0000003efa400000 8K r-x-- /lib64/libdl-2.12.so

0000003efa402000 2048K ----- /lib64/libdl-2.12.so

0000003efa602000 4K r---- /lib64/libdl-2.12.so

0000003efa603000 4K rw--- /lib64/libdl-2.12.so

0000003efb800000 116K r-x-- /lib64/libtinfo.so.5.7

0000003efb81d000 2048K ----- /lib64/libtinfo.so.5.7

0000003efba1d000 16K rw--- /lib64/libtinfo.so.5.7

00007f1a42fc8000 96836K r---- /usr/lib/locale/locale-archive

00007f1a48e59000 48K r-x-- /lib64/libnss_files-2.12.so

00007f1a48e65000 2048K ----- /lib64/libnss_files-2.12.so

00007f1a49065000 4K r---- /lib64/libnss_files-2.12.so

00007f1a49066000 4K rw--- /lib64/libnss_files-2.12.so

00007f1a49067000 12K rw--- [ anon ]

00007f1a4906b000 8K rw--- [ anon ]

00007f1a4906d000 28K r--s- /usr/lib64/gconv/gconv-modules.cache

00007f1a49074000 4K rw--- [ anon ]

00007fff48189000 84K rw--- [ stack ]

00007fff481ff000 4K r-x-- [ anon ]

ffffffffff600000 4K r-x-- [ anon ]

total 108472K

2757: -bash

0000000000400000 848K r-x-- /bin/bash

00000000006d3000 40K rw--- /bin/bash

00000000006dd000 20K rw--- [ anon ]

00000000008dc000 36K rw--- /bin/bash

0000000001385000 396K rw--- [ anon ]

0000003ef9800000 128K r-x-- /lib64/ld-2.12.so

0000003ef9a1f000 4K r---- /lib64/ld-2.12.so

0000003ef9a20000 4K rw--- /lib64/ld-2.12.so

0000003ef9a21000 4K rw--- [ anon ]

0000003ef9c00000 1576K r-x-- /lib64/libc-2.12.so

0000003ef9d8a000 2048K ----- /lib64/libc-2.12.so

0000003ef9f8a000 16K r---- /lib64/libc-2.12.so

0000003ef9f8e000 4K rw--- /lib64/libc-2.12.so

0000003ef9f8f000 20K rw--- [ anon ]

0000003efa400000 8K r-x-- /lib64/libdl-2.12.so

0000003efa402000 2048K ----- /lib64/libdl-2.12.so

0000003efa602000 4K r---- /lib64/libdl-2.12.so

0000003efa603000 4K rw--- /lib64/libdl-2.12.so

0000003efb800000 116K r-x-- /lib64/libtinfo.so.5.7

0000003efb81d000 2048K ----- /lib64/libtinfo.so.5.7

0000003efba1d000 16K rw--- /lib64/libtinfo.so.5.7

00007fda04cb1000 96836K r---- /usr/lib/locale/locale-archive

00007fda0ab42000 48K r-x-- /lib64/libnss_files-2.12.so

00007fda0ab4e000 2048K ----- /lib64/libnss_files-2.12.so

00007fda0ad4e000 4K r---- /lib64/libnss_files-2.12.so

00007fda0ad4f000 4K rw--- /lib64/libnss_files-2.12.so

00007fda0ad50000 12K rw--- [ anon ]

00007fda0ad54000 8K rw--- [ anon ]

00007fda0ad56000 28K r--s- /usr/lib64/gconv/gconv-modules.cache

00007fda0ad5d000 4K rw--- [ anon ]

00007fff0e9e0000 84K rw--- [ stack ]

00007fff0e9ff000 4K r-x-- [ anon ]

ffffffffff600000 4K r-x-- [ anon ]

total 108472K

从上面的指令上看出,pid为1464和2757两个进程使用很多相同的so文件,而且其内存地址也相同。这里个人认为rss部分的内存理论上是可以完全计算准确的。做法就是先遍历/proc下所有的pid,再pmap所有pid,对所有的输出结果进行汇总后去重。再将第二列的占用内存值求和(具体也可以考虑从/proc/pid/smaps文件入手 )。

五、其他情况

在第四步算算总帐中,我们看出 rrs内存 + slab内存 + pagetables内存 > 实际已用内存。但该情况并非是绝对的,也有例外。在我上面提到的oracle 使用场景下,事先分配了70g左右的oracle sga 空间(即内存空间)。而三者相加要远远小于实际使用的物理内存。这又要怎么解释呢?再去除cache和buffer的空间也要远远小于实际使用的内存。

[root@irora04s ~]# free -m

total used free shared buffers cached

Mem: 129023 100024 28999 0 885 12595

-/+ buffers/cache: 86543 42480

Swap: 24575 0 24575

[root@irora04s ~]# sh /tmp/mem.sh

4339696KB, 66056KB, 745.805MB

rss+pagetable+slabinfo=5046.805MB

total used free shared buffers cached

Mem: 129023 100096 28926 0 885 12597

-/+ buffers/cache: 86614 42409

Swap: 24575 0 24575

我个人的理解是事先分配的这部分sga内存,大部分是空page页,在未使用时虽然空间被占用了,但该内存地址内并不存在数据。所以一旦该机触发kdump 时,crash 的内存空间占用的磁盘空间 接近于rss+pagetable+slabinfo ,小于rss+pagetable+slabinfo+buffers+cached 。

最后这里同样推荐有时间看下nmon的源码。因为从nmon的内存统计信息来看,更便于理解内存的几个去向:

931752851afd2267e6cd87e2e2478ff5.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值