
Swap分区
Swap分区,即交换区,Swap空间的作用可简单描述为:当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap空间中,等到那些程序要运行时,再从Swap中恢复保存的数据到内存中。这样,系统总是在物理内存不够时,才进行Swap交换。 其实,Swap的调整对Linux服务器,特别是Web服务器的性能至关重要。通过调整Swap,有时可以越过系统性能瓶颈,节省系统升级费用。
众所周知,现代操作系统都实现了“虚拟内存”这一技术,不但在功能上突破了物理内存的,使程序可以操纵大于实际物理内存的空间,更重要的是,“虚拟内存”是隔离每个进程的安全保护网,使每个进程都不受其它程序的干扰。
计算机用户会经常遇这种现象。例如,在使用Windows系统时,可以同时运行多个程序,当你切换到一个很长时间没有理会的程序时,会听到硬盘“哗哗”直响。这是因为这个程序的内存被那些频繁运行的程序给“偷走”了,放到了Swap区中。因此,一旦此程序被放置到前端,它就会从Swap区取回自己的数据,将其放进内存,然后接着运行。
需要说明一点,并不是所有从物理内存中交换出来的数据都会被放到Swap中(如果这样的话,Swap就会不堪重负),有相当一部分数据被直接交换到文件系统。例如,有的程序会打开一些文件,对文件进行读写(其实每个程序都至少要打开一个文件,那就是运行程序本身),当需要将这些程序的内存空间交换出去时,就没有必要将文件部分的数据放到Swap空间中了,而可以直接将其放到文件里去。如果是读文件操作,那么内存数据被直接释放,不需要交换出来,因为下次需要时,可直接从文件系统恢复;如果是写文件,只需要将变化的数据保存到文件中,以便恢复。但是那些用malloc和new函数生成的对象的数据则不同,它们需要Swap空间,因为它们在文件系统中没有相应的“储备”文件,因此被称作“匿名”(Anonymous)内存数据。这类数据还包括堆栈中的一些状态和变量数据等。所以说,Swap空间是“匿名”数据的交换空间。
Swap配置对性能的影响
分配太多的Swap空间会浪费磁盘空间,而Swap空间太少,则系统会发生错误。
如果系统的物理内存用光了,系统就会跑得很慢,但仍能运行;如果Swap空间用光了,那么系统就会发生错误。例如,Web服务器能根据不同的请求数量衍生出多个服务进程(或线程),如果Swap空间用完,则服务进程无法启动,通常会出现“application is out of memory”的错误,严重时会造成服务进程的死锁。因此Swap空间的分配是很重要的。
通常情况下,Swap空间应大于或等于物理内存的大小,最小不应小于M,通常Swap空间的大小应是物理内存的2-2.5倍。但根据不同的应用,应有不同的配置:如果是小的桌面系统,则只需要较小的Swap空间,而大的服务器系统则视情况不同需要不同大小的Swap空间。特别是数据库服务器和Web服务器,随着访问量的增加,对Swap空间的要求也会增加,具体配置参见各服务器产品的说明。
另外,Swap分区的数量对性能也有很大的影响。因为Swap交换的操作是磁盘IO的操作,如果有多个Swap交换区,Swap空间的分配会以轮流的方式操作于所有的Swap,这样会大大均衡IO的负载,加快Swap交换的速度。如果只有一个交换区,所有的交换操作会使交换区变得很忙,使系统大多数时间处于等待状态,效率很低。用性能监视工具就会发现,此时的CPU并不很忙,而系统却慢。这说明,瓶颈在IO上,依靠提高CPU的速度是解决不了问题的。
系统性能监视
Swap空间的分配固然很重要,而系统运行时的性能监控却更加有价值。通过性能监视工具,可以检查系统的各项性能指标,找到系统性能的瓶颈。
最常用的是vmstat命令(在大多数Unix平台下都有这样一些命令),此命令可以查看大多数性能指标。 例如:
# vmstat 3
procs memory swap io system cpu
r b w swpd free buff cache si so bi bo in cs us sy id
0 0 0 0 93880 3304 19372 0 0 10 2 131 10 0 0 99
0 0 0 0 93880 3304 19372 0 0 0 0 109 8 0 0 100
0 0 0 0 93880 3304 19372 0 0 0 0 112 6 0 0 100
…………
命令说明:
vmstat 后面的参数指定了性能指标捕获的时间间隔。3表示每三秒钟捕获一次。第一行数据不用看,没有价值,它仅反映开机以来的平均性能。从第二行开始,反映每三秒钟之内的系统性能指标。这些性能指标中和Swap有关的包括以下几项:
procs下的w
它表示当前(三秒钟之内)需要释放内存、交换出去的进程数量。
memory下的swpd
它表示使用的Swap空间的大小。
Swap下的si,so
si表示当前(三秒钟之内)每秒交换回内存(Swap in)的总量,单位为kbytes;so表示当前(三秒钟之内)每秒交换出内存(Swap out)的总量,单位为kbytes。
以上的指标数量越大,表示系统越忙。这些指标所表现的系统繁忙程度,与系统具体的配置有关。系统管理员应该在平时系统正常运行时,记下这些指标的数值,在系统发生问题的时候,再进行比较,就会很快发现问题,并制定本系统正常运行的标准指标值,以供性能监控使用。
另外,使用swapon -s也能简单地查看当前Swap资源的使用情况。例如:
# swapon -s
Filename Type Size Used Priority
/dev/hda9 partition 361420 0 3
能够方便地看出Swap空间的已用和未用资源的大小。
应该使Swap负载保持在30%以下,这样才能保证系统的良好性能。
增加Swap空间
1) 成为超级用户
$su - root
2) 创建Swap文件
# dd if=/dev/zero of=swapfile bs=1024 count=65536
创建一个有连续空间的交换文件。
3) 激活Swap文件
#/usr/sbin/swapon swapfile
swapfile指的是上一步创建的交换文件。
4) 现在新加的Swap文件已经起作用了,但系统重新启动以后,并不会记住前几步的操作。因此要在/etc/fstab文件中记录文件的名字,和Swap类型,如:
/path/swapfile none Swap sw,pri=3 0 0
5) 检验Swap文件是否加上
/usr/sbin/swapon -s
怎样查看哪些程序占用了Swap分区
每个进程都会在/proc下面生成一个以进程号为名字的目录,里面的各个文件就是其在内存中的映像。其中smaps这个文件,便记载了每个进程每个数据段占用内存的情况。
1.#!/bin/bash
2.
3.###############################################################################
4.# 日期 : 2011-10-31
5.# 作者 : xiaoxi227
6.# Email : xiaoxi227@163.com
7.# QQ : 451914397
8.# 版本 : 1.0
9.# 脚本功能 : 列出正在占用swap的进程。
10.# 调用关系 :
11.# 其他说明 :
12.###############################################################################
13.
14.echo -e "PID\\Swap\\Proc_Name"
15.
16.# 拿出/proc目录下所有以数字为名的目录(进程名是数字才是进程,其他如sys,net等存放的是其他信息)
17.for pid in `ls -l /proc | grep ^d | awk '{ print $8 }'| grep -v [^0-9]`
18.do
19. # 让进程释放swap的方法只有一个:就是重启该进程。或者等其自动释放。
20. # 如果进程会自动释放,那么我们就不会写脚本来找他了,找他都是因为他没有自动释放。
21. # 所以我们要列出占用swap并需要重启的进程,但是init这个进程是系统里所有进程的祖先进程
22. # 重启init进程意味着重启系统,这是万万不可以的,所以就不必检测他了,以免对系统造成影响。
23. if [ $pid -eq 1 ];then continue;fi # Do not check init process
24. # 判断改进程是否占用了swap
25. grep -q "Swap" /proc/$pid/smaps 2>/dev/null
26. if [ $? -eq 0 ];then # 如果占用了swap
27. swap=$(grep Swap /proc/$pid/smaps \ # 占用swap的总大小(单位:KB)
28. | gawk '{ sum+=$2;} END{ print sum }')
29. proc_name=$(ps aux | grep -w "$pid" | grep -v grep \\ # 进程名
30. | awk '{ for(i=11;i<=NF;i++){ printf("%s ",$i); }}')
31. if [ $swap -gt 0 ];then # 如果占用了swap则输出其信息
32. echo -e "$pid\${swap}\$proc_name"
33. fi
34. fi
35.done | sort -k2 -n | gawk -F'\' '{ # 按占用swap的大小排序,再用awk实现单位转换。
36.# 如:将1024KB转换成1M。将1048576KB转换成1G,以提高可读性。
37. pid[NR]=$1;
38. size[NR]=$2;
39. name[NR]=$3;
40.}
41.END{
42. for(id=1;id<=length(pid);id++)
43. {
44. if(size[id]<1024)
45. printf("%-10s\%15sKB\%s\\n",pid[id],size[id],name[id]);
46. else if(size[id]<1048576)
47. printf("%-10s\%15.2fMB\%s\\n",pid[id],size[id]/1024,name[id]);
48. else
49. printf("%-10s\%15.2fGB\%s\\n",pid[id],size[id]/1048576,name[id]);
50. }
51.}'
附录一:浅谈Linux内存管理机制
一 物理内存和虚拟内存
我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念。
物理内存就是系统硬件提供的内存大小,是真正的内存,相对于物理内存,在Linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space)。
作为物理内存的扩展,Linux会在物理内存不足时,使用交换分区的虚拟内存,更详细的说,就是内核会将暂时不用的内存块信息写到交换空间,这样以来,物理内存得到了释放,这块内存就可以用于其它目的,当需要用到原始的内容时,这些信息会被重新从交换空间读入物理内存。
Linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的数据块自动交换到虚拟内存中,而将经常使用的信息保留到物理内存。
要深入了解Linux内存运行机制,需要知道下面提到的几个方面:
首先,Linux系统会不时的进行页面交换操作,以保持尽可能多的空闲物理内存,即使并没有什么事情需要内存,Linux也会交换出暂时不用的内存页面。这可以避免等待交换所需的时间。
其次,Linux进行页面交换是有条件的,不是所有页面在不用时都交换到虚拟内存,Linux内核根据”最近最经常使用“算法,仅仅将一些不经常使用的页面文件交换到虚拟内存,有时我们会看到这么一个现象:Linux物理内存还有很多,但是交换空间也使用了很多。其实,这并不奇怪,例如,一个占用很大内存的进程运行时,需要耗费很多内存资源,此时就会有一些不常用页面文件被交换到虚拟内存中,但后来这个占用很多内存资源的进程结束并释放了很多内存时,刚才被交换出去的页面文件并不会自动的交换进物理内存,除非有这个必要,那么此刻系统物理内存就会空闲很多,同时交换空间也在被使用,就出现了刚才所说的现象了。关于这点,不用担心什么,只要知道是怎么一回事就可以了。
最后,交换空间的页面在使用时会首先被交换到物理内存,如果此时没有足够的物理内存来容纳这些页面,它们又会被马上交换出去,如此以来,虚拟内存中可能没有足够空间来存储这些交换页面,最终会导致Linux出现假死机、服务异常等问题,Linux虽然可以在一段时间内自行恢复,但是恢复后的系统已经基本不可用了。
因此,合理规划和设计Linux内存的使用,是非常重要的。
二 内存的监控
作为一名Linux系统管理员,监控内存的使用状态是非常重要的,通过监控有助于了解内存的使用状态,比如内存占用是否正常,内存是否紧缺等等,监控内存最常使用的命令有free、top等,下面是某个系统free的输出:
[haixigov@WEBServer ~]$ free
total used free shared buffers cached
Mem: 102432 16360492 41940 0 465404 12714880
-/+ buffers/cache: 3180208 13222224
Swap: 8193108 2 8192844
我们解释下输出结果中每个选项的含义:
首先是第一行:
total:物理内存的总大小。
used:已经使用的物理内存多小。
free:空闲的物理内存值。
shared:多个进程共享的内存值。
buffers/cached:磁盘缓存的大小。
第二行Mem:代表物理内存使用情况。
第三行(-/+ buffers/cached):代表磁盘缓存使用状态。
第四行:Swap表示交换空间内存使用状态。
free命令输出的内存状态,可以通过两个角度来查看:一个是从内核的角度来看,一个是从应用层的角度来看的。
1.从内核的角度来查看内存的状态
就是内核目前可以直接分配到,不需要额外的操作,即为上面free命令输出中第二行Mem项的值,可以看出,此系统物理内存有16G,空闲的内存只有41940K,也就是40M多一点,我们来做一个这样的计算:
102432-16360492=41940
其实就是总的物理内存减去已经使用的物理内存得到的就是空闲的物理内存大小,注意这里的可用内存值41940并不包含处于buffers和cached状态的内存大小。
如果你认为这个系统空闲内存太小,那你就错了,实际上,内核完全控制着内存的使用情况,Linux会在需要内存的时候,或在系统运行逐步推进时,将buffers和cached状态的内存变为free状态的内存,以供系统使用。
2.从应用层的角度来看系统内存的使用状态
也就是Linux上运行的应用程序可以使用的内存大小,即free命令第三行“(-/+ buffers/cached)”的输出,可以看到,此系统已经使用的内存才3180208K,而空闲的内存达到13222224K,继续做这样一个计算:
41940+(465404+12714880)=13222224
通过这个等式可知,应用程序可用的物理内存值是Mem项的free值加上buffers和cached值之和,也就是说,这个free值是包括buffers和cached项大小的,
对于应用程序来说,buffers/cached占有的内存是可用的,因为buffers/cached是为了提高文件读取的性能,当应用程序需要用到内存的时候,buffers/cached会很快地被回收,以供应用程序使用。
3.buffers与cached的异同
在 Linux 操作系统中,当应用程序需要读取文件中的数据时,操作系统先分配一些内存,将数据从磁盘读入到这些内存中,然后再将数据分发给应用程序;当需要往文件中写数据时,操作系统先分配内存接收用户数据,然后再将数据从内存写到磁盘上。然而,如果有大量数据需要从磁盘读取到内存或者由内存写入磁盘时,系统的读写性能就变得非常低下,因为无论是从磁盘读数据,还是写数据到磁盘,都是一个很消耗时间和资源的过程,在这种情况下,Linux引入了buffers和cached机制。
buffers与cached都是内存操作,用来保存系统曾经打开过的文件以及文件属性信息,这样当操作系统需要读取某些文件时,会首先在buffers与cached内存区查找,如果找到,直接读出传送给应用程序,如果没有找到需要数据,才从磁盘读取,这就是操作系统的缓存机制,通过缓存,大大提高了操作系统的性能。但buffers与cached缓冲的内容却是不同的。
buffers是用来缓冲块设备做的,它只记录文件系统的元数据(metadata)以及 tracking in-flight pages,而cached是用来给文件做缓冲。更通俗一点说:buffers主要用来存放目录里面有什么内容,文件的属性以及权限等等。而cached直接用来记忆我们打开过的文件和程序。
为了验证我们的结论是否正确,可以通过vi打开一个非常大的文件,看看cached的变化,然后再次vi这个文件,感觉一下两次打开的速度有何异同,是不是第二次打开的速度明显快于第一次呢?
接着执行下面的命令:
find /* -name *.conf
看看buffers的值是否变化,然后重复执行find命令,看看两次显示速度有何不同。
Linux操作系统的内存运行原理,很大程度上是根据服务器的需求来设计的,例如系统的缓冲机制会把经常使用到的文件和数据缓存在cached中,Linux总是在力求缓存更多的数据和信息,这样再次需要这些数据时可以直接从内存中取,而不需要有一个漫长的磁盘操作,这种设计思路提高了系统的整体性能。
三 交换空间swap的使用
虽然现在的内存已经变得非常廉价,但是swap仍然有很大的使用价值,合理的规划和使用swap分区,对系统稳定运行至关重要。Linux下可以使用文件系统中的一个常规文件或者一个分区作为交换空间使用。同时Linux允许使用多个交换分区或者交换文件。
1.创建swap交换空间
创建交换空间所需的交换文件是一个普通的文件,但是,创建交换文件与创建普通文件不同,必须通过dd命令来完成,同时这个文件必须位于本地硬盘上,不能在网络文件系统(NFS)上创建swap交换文件。例如:
[root@localhost ~]# dd if=/dev/zero of=/data/swapfile bs=1024 count=65536
65536+0 records in
65536+0 records out
这样就创建一个有连续空间的交换文件,大小为60M左右,关于dd命令做简单的讲述:
if=输入文件,或者设备名称。
of=输出文件或者设备名称。
ibs=bytes 表示一次读入bytes 个字节(即一个块大小为 bytes 个字节)。
obs=bytes 表示一次写bytes 个字节(即一个块大小为 bytes 个字节)。
bs=bytes,同时设置读写块的大小,以bytes为单位,此参数可代替 ibs 和 obs。
count=blocks 仅拷贝blocks个块。
skip=blocks 表示从输入文件开头跳过 blocks 个块后再开始复制。
seek=blocks表示从输出文件开头跳过 blocks 个块后再开始复制。(通常只有当输出文件是磁盘或磁带时才有效)
这里的输入设备/dev/zero代表一个输出永远为0的设备文件,使用它作输入可以得到全为空的文件。
2.激活和使用swap
首先通过mkswap命令指定作为交换空间的设备或者文件:
[root@localhost ~]#mkswap /data/swapfile
Setting up swapspace version 1, size = 67104 kB
[root@localhost backup]# free
total used free shared buffers cached
Mem: 2066632 199**** ****4 0 26160 1588044
-/+ buffers/cache: 383984 16828
Swap: 4088500 101036 39874
从上面输出可知,我们指定了一个67104 kB的交换空间,而此时新建的交换空间还未被使用,下面简单介绍下mkswap命令,mkswap的一般使用格式为:
mkswap [参数] [设备名称或文件][交换区大小]
参数:
-c:建立交换区前,先检查是否有损坏的区块。
-v0:建立旧式交换区,此为预设值。
-v1:建立新式交换区。
交换区大小:指定交换区的大小,单位为1024字节。
设置交换分区后,接着通过swapon命令激活swap:
[root@localhost ~]#/usr/sbin/swapon /data/swapfile
[root@localhost backup]# free
total used free shared buffers cached
Mem: 2066632 199**** ****4 0 27404 1588880
-/+ buffers/cache: 381384 1685248
Swap: 4154028 100976 4053052
通过free命令可以看出,swap大小已经由4088500k变为4154028k,相差的值是60M左右,刚好等于我们增加的一个交换文件大小,这说明新增的交换分区已经可以使用了,但是如果Linux重启,那么新增的swap空间将变得不可用,因此需要在/etc/fstab中添加自动加载设置:
/data/swapfile none swap sw 0 0
如此以来,Linux在重启后就可以实现自动加载swap分区了。其实Linux在启动过程中会执行“swapon -a”命令,此命令会加载列在/etc/fstab中的所有交换空间。
3.移除swap
通过swapoff即可移除一个交换空间
[root@localhost ~]#/usr/sbin/swapoff /data/swapfile
其实也可以通过“swapoff -a”移除在/etc/fstab中定义的所有交换空间,这里的“swapoff -a”与上面提到的“swapon -a”对应。执行“swapoff -a”后,free命令输出如下:
[root@localhost backup]# free
total used free shared buffers cached
Mem: 2066632 2048724 17908 0 30352 12748
-/+ buffers/cache: 375624 1691008
Swap: 0 0 0
附录二:手工释放Linux内存
当在Linux下频繁存取文件后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching。这个问题,貌似有不少人在问,不过都没有看到有什么很好解决的办法。那么我来谈谈这个问题。
一、通常情况
先来说说free命令:
引用
[root@server ~]# free -m
total used free shared buffers cached
Mem: 249 163 86 0 10 94
-/+ buffers/cache: 58 191
Swap: 511 0 511
其中:
引用
total 内存总数
used 已经使用的内存数
free 空闲的内存数
shared 多个进程共享的内存总额
buffers Buffer Cache和cached Page Cache 磁盘缓存的大小
-buffers/cache 的内存数:used – buffers – cached
+buffers/cache 的内存数:free + buffers + cached
可用的memory=free memory+buffers+cached。
有了这个基础后,可以得知,我现在used为163MB,free为86MB,buffer和cached分别为10MB,94MB。
那么我们来看看,如果我执行复制文件,内存会发生什么变化.
引用
[root@server ~]# cp -r /etc ~/test/
[root@server ~]# free -m
total used free shared buffers cached
Mem: 249 244 4 0 8 174
-/+ buffers/cache: 62 187
Swap: 511 0 511
在我命令执行结束后,used为244MB,free为4MB,buffers为8MB,cached为174MB,天呐,都被cached吃掉了。别紧张,这是为了提高文件读取效率的做法。
为 了提高磁盘存取效率,Linux做了一些精心的设计,除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换),还采取了两种主要 Cache方式:Buffer Cache和Page Cache。前者针对磁盘块的读写,后者针对文件inode的读写。这些Cache有效缩短了 I/O系统调用(比如read,write,getdents)的时间。
那么有人说过段时间,linux会自动释放掉所用的内存。等待一段时间后,我们使用free再来试试,看看是否有释放?
引用
[root@server test]# free -m
total used free shared buffers cached
Mem: 249 244 5 0 8 174
-/+ buffers/cache: 61 188
Swap: 511 0 511
似乎没有任何变化。(实际情况下,内存的管理还与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.
三、我的意见
上述文章就长期以来很多用户对Linux内存管理方面的疑问,给出了一个比较“直观”的回复,我更觉得有点像是核心开发小组的妥协。
对于是否需要使用这个值,或向用户提及这个值,我是有保留意见的:
引用
1、从man可以看到,这值从2.6.16以后的核心版本才提供,也就是老版的操作系统,如红旗DC 5.0、RHEL 4.x之前的版本都没有;
2、若对于系统内存是否够用的观察,我还是原意去看swap的使用率和si/so两个值的大小;
用户常见的疑问是,为什么free这么小,是否关闭应用后内存没有释放?
但实际上,我们都知道这是因为Linux对内存的管理与Windows不同,free小并不是说内存不够用了,应该看的是free的第二行最后一个值:
引用
-/+ buffers/cache: 58 191
这才是系统可用的内存大小。
实际项目中告诉我们,如果因为是应用有像内存泄露、溢出的问题,从swap的使用情况是可以比较快速可以判断的,但free上面反而比较难查看。
相反,如果在这个时候,我们告诉用户,修改系统的一个值,“可以”释放内存,free就大了。用户会怎么想?不会觉得操作系统“有问题”吗?
所以说,我觉得既然核心是可以快速清空buffer或cache,也不难做到(这从上面的操作中可以明显看到),但核心并没有这样做(默认值是0),我们就不应该随便去改变它。
一般情况下,应用在系统上稳定运行了,free值也会保持在一个稳定值的,虽然看上去可能比较小。
当发生内存不足、应用获取不到可用内存、OOM错误等问题时,还是更应该去分析应用方面的原因,如用户量太大导致内存不足、发生应用内存溢出等情况,否则,清空buffer,强制腾出free的大小,可能只是把问题给暂时屏蔽了。
我觉得,排除内存不足的情况外,除非是在软件开发阶段,需要临时清掉buffer,以判断应用的内存使用情况;或应用已经不再提供支持,即使应用对内存的时 候确实有问题,而且无法避免的情况下,才考虑定时清空buffer。(可惜,这样的应用通常都是运行在老的操作系统版本上,上面的操作也解决不了)。
附录三:cpu与memory优化学习笔记
一、CPU优化
grep HZ /boot/config-2.6.18-128.el5 (安装系统时内核编译的配置文件)
# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
CONFIG_HZ_1000=y —> 1000/s
CONFIG_HZ=1000
CONFIG_MACHZ_WDT=m
上面有HZ的表示每秒钟产生时钟中断的次数
1.编译内核
make menuconfig 按照要求选择内核,然后保存退出,就会在目录下生成:
.config
(1)make
(2)make modules
(3)make modules_install
(4)make install
(5)ls /lib/modules/2.6.26/
(6)depmod –> /lib/modules/2.6.26/modules.dep
2.单CPU
2.1 调整CPU算法中优先级(vim优先,筛质数靠后)
vim 多占几个时间间隔
质数 少占几个时间间隔
上述时间间隔称为时间片:5ms – 800ms —> 5ms => CPU中断250HZ的时候
2.2 linux优先级设定
(1)静态:实时(real time) –> 假设 0 - 99 数值越低优级越高。
(2)动态:分时 nice值(-20 - 19) —> nice值根据父进程的nice产生
[root@vlinux ~]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 2569 2567 0 75 0 – 1355 wait pts/0 00:00:01 bash
4 R 0 23 2569 0 77 0 – 1196 – pts/0 00:00:00 ps
通过命令修改进程的nice值:
renice -20 2569 —> 修改进程 2569 的nice值,然后再次查看:
[root@vlinux ~]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 2569 2567 0 60 -20 – 1355 wait pts/0 00:00:01 bash
4 R 0 21 2569 0 60 -20 – 1196 – pts/0 00:00:00 ps
可以发现nice值已经变成-20了,同时bash产生的子进程的nice也变成了-20,所以可以看出子进程会继承父进程的nice值。
给子进程指定nice值:
[root@vlinux ~]# nice -n 19 ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 2569 2567 0 60 -20 – 1355 wait pts/0 00:00:01 bash
4 R 0 65 2569 0 76 -1 – 1196 – pts/0 00:00:00 ps
可以发现子进程的nice=(父进程nice)+19=-1
编写一个c程序用于测试:
while.c
int main()
{
long count = 0;
for(count=0;count<200000000000;count++) {}
}
------> 配合 renice 命令实验
chrt命令是修改进程的静态优先级参数说明:-p 指定pid,-r 调度算法 ,或者直接跟命令。
[root@vlinux ~]# chrt 1 ./while —> 设置 ./while 进程的静态优先级(实时)
[root@vlinux ~]# chrt -p -r 10 2 —> -p:pid:2,-r:rr(轮询算法)
[root@vlinux ~]# ps -p 2 -o cls,cmd —> cls显示分类
CLS CMD
FF [migration/0]
FF为RT状态的进程,通过top命令查看RT状态进程
3.多CPU
RHEL4要加smp内核模块以支持对称多处理,如果7个cpu的话,按照进程2,2,2,1分配
mpstat 用于监控多个cpu的负载。
监控指定cpu的负载:mpstat -P 0 1
//每1秒当前系统第一个cpu, -P 指定cpu,从0开始。
taskset set or get the affinity of a process => affinity 亲和力
[root@stu18 /]# taskset
-p, –pid operate on existing given pid
-c, –cpu-list display and specify cpus in list format
-h, –help display this help
-v, –version output version information
The default behavior is to run a new command:
taskset 03 sshd -b 1024
You can retrieve the mask of an existing task:
taskset -p 700
Or set it:
taskset -p 03 700
List format uses a comma-separated list instead of a mask:
taskset -pc 0,3,7-11 700
taskset -c 0 ./while —> 指定0号cpu亲和力
二、memory 内存调优
主机实际内存地址:CPU与内存的总线(地址总线,控制总线,数据总线)
硬件支持的内存大小取决于地址总线为位数,例如32位数据总线,支持最大内存就是2的32次方,也就是4G。
操作系统的为进程提供的寻址空间:进程通过操作系统映射的虚拟地址访问实际内存,实际内存对进程是透明的。32位操作系统能提供4G的虚拟寻址空间。
所以说硬件支持的内存大小和操作系统的支持的寻址空间大小是两个不同的概念。
内存和硬盘的速度比较:
内存时间单位:ns,硬盘时间单位:ms
ms ->1000 => us ->1000 => ns
使用内存的对象 => 内核,进程,缓存(buffer,cache),IPC(共享内存->进程通信)
调优手段:
内核 —>重新编译,重新定制
进程 —> 使用
缓存 —> 使用策略节省内存
IPC -> share memory,msq(message queue),sem(signal)
1. 进程对内核使用调优
系统对寻址空间的映射关系:
最高地址:ffffffff
1G内核使用
参数和环境变量
栈(stack)段
中间段用于共享库
堆段
bss段
data段
txt段
最低地址:00000000
(1)上图中1G内存空间交给内核使用
(2)上图的00000000地址就是C 程序里 NULL所指向的地址
(3)txt段中存放程序中的函数地址 T
(4)data段里存储程序的已初始化全局变量 D
(5)bss段里存储程序的未初始化全局变量 B
(6)bss段的上层为堆段
(7)4G内存地址空间的大致中间段用于共享库
(8)1G下层位置存放进程的参数和环境变量
(9)参数下层为栈(stack)段 –> 存放栈内容
内存使用 、分配、
[root@vlinux ~]# ulimit –a //显示所有参数
core file size (blocks, -c) 0 //应用程序调试文件
data seg size (kbytes, -d) unlimited //
max nice (-e) 0
file size (blocks, -f) unlimited //访问文件的最大size
pending signals (-i) 16384 //最大未处理信号数
max locked memory (kbytes, -l) 32 //内存锁
max memory size (kbytes, -m) unlimited //最大物理内存
open files (-n) 1024 //最多打开文件数
pipe size (512 bytes, -p) 8 //匿名管道大小4KB,影响进程通信的吞吐量 find
POSIX message queues (bytes, -q) 819200 //消息队列
max rt priority (-r) 0 //实时优先级 (RT PRI)
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited //cpu使用时间
max user processes (-u) 16384 //用户进程数
virtual memory (kbytes, -v) unlimited //虚内存
file locks (-x) unlimited //文件锁数量
ulimit 只能外部命令,而不能内部命令。
2. 内存缓存(buffer,cache)调优策略
存在buffer,cache里未同步到硬盘里的数据叫脏数据,系统有相应的策略对这些数据进行同步以保证数据的安全,和提高内存使用率。
2.1周期性策略:
[root@vlinux ~]# cat /proc/sys/vm/dirty_writeback_centisecs
499
//系统自动4.99秒同步一次,可以修改这个值设定系统同步周期。
2.2超时策略:
[root@vlinux ~]# cat /proc/sys/vm/dirty_expire_centisecs
2999
//数据在buffer里的时间超过29.99秒,就同步。
2.3单进程策略:
[root@vlinux ~]# cat /proc/sys/vm/dirty_ratio
40
//当一进程产生的数据量达到内存的40%时同步。
2.4总体数据量策略:
[root@vlinux ~]# cat /proc/sys/vm/dirty_background_ratio
10
//内存总量剩余10%时就同步。
可以根据实际情况对以上四个参数的进行更改,达到对内存的调优
2.5手工同步策略:
在访问量高的时候作一个计划任务手工同步脏数据,有三种同步模式:
echo 1> /proc/sys/vm/drop_caches
//同步pagecache,这种方式比较常用(推荐使用)。
echo 2> /proc/sys/vm/drop_caches
//同步 dentries and inodes
echo 1> /proc/sys/vm/drop_caches
//同步pagecache, dentries and inodes
3 增加内存(交换空间swap)
3.1增加同一个磁盘上的交换内存
[root@vlinux ~]# swapon -s
Filename Type Size Used Priority
/dev/sda7 partition 2048248 0 -1
Priority:-1 => 现还未使用
方法一
[root@vlinux ~]# mkswap /dev/sda10 —> swap分区
[root@vlinux ~]# swapon /dev/sda10 —> 启用swap分区
方法二
[root@vlinux ~]# dd if=/dev/zero of=/tmp/swapfile bs=1024 count=1000000 —> swap文件
[root@vlinux ~]# mkswap /tmp/swapfile
[root@vlinux ~]# swapon /tmp/swapfile
3.2并行交换空间 —> 分别两个磁盘
设置swap分区优先级相同
[root@vlinux ~]#swapoff
[root@vlinux ~]# swapon -p 5 /dev/sda8
[root@vlinux ~]# swapon -p 5 /dev/sdb9
[root@vlinux ~]# vim /etc/fstab
LABEL=SWAP-sda8 swap swap defaults,pri=5 0 0
LABEL=SWAP-sdb8 swap swap defaults,pri=5 0 0
pri上限:32767 => 越高越优先
内存与swap交换可调参数:
[root@vlinux ~]# cat /proc/sys/vm/swap_token_timeout // 2.6.20后取消了这个参数
300
//这个参数是表示数据在内存里存在了300s就必须交换到swap空间里去。
[root@vlinux ~]# cat /proc/sys/vm/page-cluster
3
//表示每次交换的大小:2的3次方再乘以4K,如果参数是4就是:2的4次方乘以4K
[root@vlinux ~]# cat /proc/sys/vm/swappiness
60
//系统愿意使用swap空间的程度,60%
3. tmpfs调优
tmpfs文件系统的特点:
动态占用内存;速度快,完全在RAM中;频繁读写不损伤介质;重启不保留数据;
许多进程间通信的时候一般都在 /tmp 目录底下创建s|p文件,例如:apache+php的网站,可能在/tmp建立很多临时文件,比如session或者一些缓存文件。这时我们可以考虑将内存中的一部分空间拿出来挂载在 /tmp目录下以提高效率。
方法一
mkdir /dev/shm/tmp
chmod 1777 /dev/shm/tmp/
mount –bind /dev/shm/tmp/ /tmp
方法二
mkdir /tmpfs
mount -t tmpfs -o size=1G tmpfs /tmpfs //挂载tmpfs,一般size为100MB即可
mount –bind /tmpfs /tmp
也可以更改fstab文件
测试更改以后的效果:
dd if=/dev/zero of=/tmp/bigfile bs=1024 count=300000
可以看到写入的速度有了很大的提高
4. IPC调优
[root@vlinux ~]# ipcs
—— Shared Memory Segments ——–
key shmid owner perms bytes nattch status
0×00000000 0 root 4 40 2
0×00000000 32769 root 4 16384 2
0×00000000 65538 root 4 268 2
0×00000000 98307 root 4 36 2
0×00000000 131076 root 4 16384 2
0×00000000 163845 root 4 268 2
—— Semaphore Arrays ——–
key semid owner perms nsems
0×000000a7 0 root 600 1
—— Message Queues ——–
key msqid owner perms used-bytes messages
3.1 共享内存区 Shared Memory Segment —> 默认大小
(1)进程通信量比较大的时候使用共享内存
(2)Web 或 Oracle –> 一般用不上共享内存,可以将共享内存调小一些
ipcrm [ -q msgid | -Q msgkey | -s semid | -S semkey | -m shmid | -M shmkey ]
cat /proc/sys/kernel/shmall => 268435456:共享内存总量,单位:页数
cat /proc/sys/kernel/shmmax => 4294967295:单个系统共享内存大小,单位:字节
cat /proc/sys/kernel/shmmni => 4096 :系统享内存个数
man proc 查看参数说明
3.2 消息队列 Message Queues —> 默认大小1MB
(1)进程通信量比较小的时候使用消息队列
(2)消息个数,单个消息大小,消息队列总长度
cat /proc/sys/kernel/msgmax => 65536:单个消息队列长度,单位字节
cat /proc/sys/kernel/msgmni => 16:消息队列个数
cat /proc/sys/kernel/msgmnb => 65536:单个消息最大大小,单位字节
3.3 信号量/旗语 数组 Semaphore Arrays => 信号量是一个数组
(1)用于进程间互斥机制 –> 比如对文件进行加锁 => 读:共享锁,写:互斥锁
(2)数组里存放共享锁和互斥锁的标记
cat /proc/sys/kernel/sem => 250 32000 32 128
SEMMSL:250 –> 信号量元素个数
SEMMNS:32000 –> 信号量元素总数
SEMOPM:32 –> 自定义对信号量元素操作
SEMMNI:128 –> 信号量个数
echo 250 32000 32 128 > /proc/sys/kernel/sem
