因此,我试图对交换使用率较高的系统中的交换使用来自何处进行一些调查:
# free
total used free shared buffers cached
Mem: 515324 508800 6524 0 4852 27576
-/+ buffers/cache: 476372 38952
Swap: 983032 503328 479704
添加每个进程使用的交换空间:
# for proc in /proc/*; do cat $proc/smaps 2>/dev/null | awk '/Swap/{swap+=$2}END{print swap "\t'`readlink $proc/exe`'"}'; done | sort -n | awk '{total+=$1}/[0-9]/;END{print total "\tTotal"}'
0 /bin/gawk
0 /bin/sort
0 /usr/bin/readlink
28 /sbin/xxxxxxxx
52 /sbin/mingetty
52 /sbin/mingetty
52 /sbin/mingetty
52 /sbin/mingetty
56 /sbin/mingetty
56 /sbin/mingetty
60 /xxxxxxxxxxx
60 /usr/sbin/xxx
84 /usr/sbin/xxx
108 /usr/bin/xxx
168 /bin/bash
220 /sbin/init
256 /sbin/rsyslogd
352 /bin/bash
356 /bin/bash
360 /usr/sbin/sshd
496 /usr/sbin/crond
672 /usr/sbin/sshd
12972 /opt/jdk1.6.0_22/bin/java
80392 /usr/libexec/mysqld
311876 /opt/jdk1.6.0_22/bin/java
408780 Total
这给出了总已使用交换的较低值。剩余的已用交换空间在哪里?它是内核中经过 vmalloc() 处理的内存吗?还有别的事吗?我怎样才能识别它?
内存信息的输出:
# cat /proc/meminfo
MemTotal: 515324 kB
MemFree: 6696 kB
Buffers: 5084 kB
Cached: 28056 kB
SwapCached: 157512 kB
Active: 429372 kB
Inactive: 65068 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 515324 kB
LowFree: 6696 kB
SwapTotal: 983032 kB
SwapFree: 478712 kB
Dirty: 100 kB
Writeback: 0 kB
AnonPages: 399456 kB
Mapped: 8792 kB
Slab: 7744 kB
PageTables: 1820 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
CommitLimit: 1240692 kB
Committed_AS: 1743904 kB
VmallocTotal: 507896 kB
VmallocUsed: 3088 kB
VmallocChunk: 504288 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
Hugepagesize: 4096 kB
答案1
您观察到的差异实际上并不是由于交换空间未被考虑在内。内核有时附加到/proc/*/exe
链接的“(已删除)”是由 awk 脚本输出的readlink
,并且会导致 awk 脚本中的解析错误,并且您实际上不计算其二进制文件不再存在于总数中的进程。
/proc/*/exe
当进程的原始可执行文件不再存在时,某些内核会将“(已删除)”一词附加到符号链接目标。
您的命令显示的数量少于总数的原因就是因为这个。此类链接的输出readlink
将类似于“/path/to/bin(已删除)”,这会在将awk
输出替换回字符串时导致解析错误(它不喜欢括号和空格)。例如,执行以下操作:
for a in /proc/*/exe ; do readlink $a ; done | grep deleted
您将看到一些附加了“(已删除)”的条目。如果您查看这些条目的交换使用情况,它们的总数将与您看到的差异相匹配,因为由此产生的awk
错误会阻止计算它们的总数并将其包含在最终总数中。
如果您运行原始命令而不在任何地方重定向 stderr,您可能会注意到一些“失控字符串常量”错误。这些错误是上述原因造成的,您不应该忽略它们。
忽略对原始命令的其他潜在改进,您可以通过删除“(已删除)”来修改它,如下所示(注释|awk '{print $1}'
添加到readlink
输出中):
for proc in /proc/*; \
do cat $proc/smaps 2>/dev/null | awk '/Swap/{swap+=$2}END{print swap "\t'`readlink $proc/exe|awk '{print $1}' `'" }'; \
done | sort -n | awk '{total+=$1}/[0-9]/;END{print total "\tTotal"}'
如果名称包含空格,则使用awk
来修复 的输出可能会中断 - 您可以使用或任何您喜欢的方法。readlink
sed
奖金信息
顺便说一句,你可以只使用smem -t
. “交换”列显示您想要的内容。
不过,至于自己计算,您还可以更直接地从字段VmSwap
中获取此信息/proc/*/status
(smaps 需要一些内核支持,并且并不总是可用),并避免通过使用适当的文件名模式来重定向错误输出,从而避免错误开头:
for proc in /proc/[0-9]*; do \
awk '/VmSwap/ { print $2 "\t'`readlink $proc/exe | awk '{ print $1 }'`'" }' $proc/status; \
done | sort -n | awk '{ total += $1 ; print $0 } END { print total "\tTotal" }'
如果您不需要实际的二进制文件并且只需处理进程名称即可处理,那么您可以获得一切从status
:
for a in /proc/*/status ; do \
awk '/VmSwap|Name/ { printf $2 " " } END { print "" }' $a ; \
done | awk '{ total+=$2 ; print $0 } END { print "Total " total }'
最后,如果只拥有 PID 就足够了,您可以使用以下命令完成这一切awk
:
awk '/VmSwap/ { total += $2; print $2 "\t" FILENAME } END { print total "\tTotal" }' /proc/*/status
笔记:
free
现在这并不是说和之间没有差异smem
(后者与您的脚本相同)。有很多(例如,参见https://www.google.com/search?q=smem+free,第一页上的结果足以回答您有关内存使用情况的问题)。但如果没有适当的测试,就无法解决您的具体情况。
答案2
如果内核需要更多可用内存或者只是因为一段时间未使用,tmpfs 也会使用交换...因此任何 tmpfs 使用都可能会消耗交换。