Solaris 8内存管理机制研究吴海燕 戚丽 冯珂摘 要:寻找性能瓶颈是性能分析中的一项重要任务,内存瓶颈的表现并不像CPU或磁盘那样直接,本文通过对Solaris 8内存管理机制的研究,给出了寻找Solaris 8系统内存瓶颈的方法。
关键词:Solaris 8,内存管理,性能优化一、问题的提出清华大学计算机与信息管理中心数据中心现有服务器近百台,其中包括了SUN Fire 15000、SUN Enterprise 5500、SUN Enterprise 5000等大型SUN服务器,Solaris 8是主流操作系统。
为了对服务器的资源(如CPU、内存、磁盘、网络)的使用情况进行长期监控,建立性能优化(performance tuning)的基准值,我们开发了一套脚本程序定时采集系统运行参数。
在长期的监控中,我们发现Solaris 8系统的空闲内存(freemem)呈现一个有趣的变化规律,如图1所示:图1 空闲内存(freemem)变化图图1是某Solaris 8系统(在下文中我们称之为15k-a)自2003年2月份以来的freemem 变化情况,横坐标是时间,纵坐标是freemem的数量,以8K字节为单位。
15k-a配置是10路Super SPARCIII CPU,10GB物理内存。
从上图可以看到在正常运行时,freemem应该是比较稳定的,15k-a主要是运行数据库,数据库在运行时会占用2G内存作为SGA区使用,因此在通常的负载下,freemem保持在6~7G之间是比较正常的。
稳定一段时间后,15k-a的freemem会持续走低,直到最低值,约为18893×8KMB,然后系统开始回收内存,我们就会看到freemem数量急剧上升。
freemem的陡降都发生在凌晨1:00之后,检查系统作业发现每天1:00都会有一个数据库备份脚本开始运行:首先是用“exp”命令给数据库做逻辑备份,然后用“cp”命令把备份出来的文件拷贝到后备存储上。
这两个命令都是正常退出,没有任何报错。
开始时我们曾怀疑是有内存泄漏,当某一天freemem大幅攀升时,此怀疑被解除了,因为如果有内存泄漏,系统是无法将内存回收回来的。
对于一个物理内存为10GB的系统来说,如果空闲内存(freemem)真的减少到不到二百兆,那将存在着严重的问题。
但奇怪的是系统的CPU使用率一直很低,所有进程的反应也很快,系统没有任何资源匮乏的迹象。
如何解释这些问题呢,为此我们对Solaris 2.x 的内存管理机制进行了研究。
二、Solaris的内存管理机制Solaris 8的内存管理为虚拟内存管理。
[1]简单地说,虚拟内存就是进程看到比它实际使用的物理内存多得多的内存空间,对于64位的Solaris 8操作系统,进程可以通过8K 大小的段寻址访问2的64次方字节的内存空间,这种8K的段被称为页(page)。
传统的UNIX通过进程(pagedaemon)完成虚拟地址和物理地址间的转换,在Solaris中这些是通过一个硬件-MMU(Memory Management Unit)-来实现的。
在多处理器系统中,每个CPU 都有自己的MMU。
Solaris 8的虚拟存储体系由系统寄存器、CPU CACHE、主存(RAM,物理内存)、外存(磁盘、磁带等)构成。
有两个基本的虚拟内存系统管理模型[2]:交换(swapping)和按需换页(demand paged)模型。
交换模型的内存管理粒度是用户进程,当内存不足时,最不活跃的进程被交换出内存(swapping out)。
按需换页模型的内存管理粒度是页(page),当内存匮乏时,只有最不经常使用的页被换出。
Solaris 8结合使用了这两种内存管理模型,在通常情况下使用按需换页模型,当内存严重不足时,使用交换模型来进行内存释放。
与传统UNIX系统相比,Solaris虚拟内存系统的功能要丰富得多,它负责管理所有与I/O和内存相关的对象,包括内核、用户应用程序、共享库和文件系统。
传统的UNIX系统V(System V)使用一个单独的缓冲区来加速文件系统的I/O, Solaris 8则使用虚拟内存系统来管理文件系统的缓存,系统的所有空闲内存都可以被用来做为文件I/O缓存,因为RAM的访问速度比磁盘快得多,所以这样做带来的性能提高是可观的。
这也意味着在存在大量文件系统I/O的系统上,空闲内存的数量几乎是0。
了解系统内存被分配到了什么地方,系统在什么情况下进行内存整理是系统管理的重要任务之一。
有了上面的基础知识,我们就可以回答这个问题了。
2.1 Solaris是如何分配物理内存的要知道一个Solaris系统的内存都被用到了什么地方,首先需要确定系统的物理内存数量,如下例所示:bash-2.03$ /usr/sbin/prtconf | grep MemoryMemory size: 8192 Megabytes在上面的例子中,系统的物理内存为8G字节。
一般来说Solaris 8物理内存的使用可分为内核保留内存、进程(包括系统进程和用户进程)内存、文件系统缓存和空闲内存四块,下面分别描述。
内核使用的内存:被映射到内核的地址空间。
随着内核模块、驱动程序载入和退出,数量会有所变化。
可以使用sar命令显示内核使用的内存数量,如下例所示:bash-2.03$ sar -k 1SunOS sun-15k-a 5.8 Generic_108528-20 sun4u 05/21/0315:01:00 sml_mem alloc fail lg_mem alloc fail ovsz_alloc fail15:01:01 51806720 31842570 0 588922880 557618688 0 149225472 0上例中内核使用了31842570+557618688+149225472=738686730字节,即约740M字节。
crash命令可以详细地显示内核内存是如何分配的。
进程内存,被映射到进程的地址空间。
一般包括系统daemon(如cron、syslogd等)使用的内存、CDE环境需要的内存、数据库引擎使用的内存、用户分时程序使用的内存等。
pmap命令显示了进程是如何使用内存的:bash-2.03$ pmap -x 1921419214: -bashAddress Kbytes Resident Shared Private Permissions Mapped File00010000 432 432 432 - read/exec bash0008A000 80 80 72 8 read/write/exec bash0009E000 152 152 112 40 read/write/exec [ heap ]FF100000 688 688 688 - read/exec libc.so.1FF1BC000 32 32 32 - read/write/exec libc.so.1FF200000 568 568 568 - read/exec libnsl.so.1FF29E000 40 40 40 - read/write/exec libnsl.so.1FF2A8000 24 16 16 - read/write/exec libnsl.so.1FF2E0000 8 8 8 - read/write/exec [ anon ]FF2F0000 16 16 16 - read/exec libmp.so.2FF304000 8 8 8 - read/write/exec libmp.so.2FF310000 8 8 8 - read/exec libc_psr.so.1FF320000 40 40 40 - read/exec libsocket.so.1FF33A000 8 8 8 - read/write/exec libsocket.so.1FF340000 168 120 120 - read/exec libcurses.so.1FF37A000 32 32 32 - read/write/exec libcurses.so.1FF382000 8 8 8 - read/write/exec libcurses.so.1FF390000 8 8 8 - read/exec libdl.so.1FF3A0000 8 8 - 8 read/write/exec [ anon ]FF3B0000 160 160 160 - read/exec ld.so.1FF3E8000 8 8 - 8 read/write/exec ld.so.1FFBEC000 16 16 8 8 read/write [ stack ]-------- ------ ------ ------ ------total Kb 2512 2456 2384 72上面的例子显示了一个bash进程的地址空间占用2512K字节的内存,其中2456K字节驻留在物理内存,2384K字节是与其它进程共享的,此bash进程有72K字节的私有数据。
如果再有一个bash进程被启动,它将共享例子中的bash进程的一些内存结构,在计算进程使用的物理内存数量时,这部分不应该重复计算。
文件系统缓存,不被映射到任何地址空间。
对用户来说这部分内存是不可见的,也是最令人迷惑的。
当你第二次打开一个大文件时,会发现速度比第一次打开同样的文件快很多,这个速度的提高也得益于这部分内存。
当一个进程运行结束时,进程地址空间中的私有部分(如该进程所独有的数据、堆栈等)所占用的页被释放,页被加入到空闲内存中,但这个进程打开文件使用的缓存页却没有被释放,与文件相关的inode 缓存被标记为不活动,被放到可用inode缓存列表的尾部。
当文件被再次打开时,与文件相关的inode缓存和文件使用的缓存页都将被复用,减少磁盘I/O,提高性能。
空闲内存(free memory):没有被用到上面三个地方的物理内存,没有被映射到任何地址空间,当新进程启动或正在运行的进程需要分配内存时,就会从这里获取内存页。
2.2 Solaris的内存管理活动Solaris 8物理内存的管理是基于页的(传统UNIX是基于段的),也就是说,所有物理内存调度是以页为单位的。
在系统级,大多数活动围绕着物理内存页的管理。
物理内存页可以为用户进程通过虚拟内存管理器使用,虚拟内存管理器可以管理除了由内核程序及其相关数据结构使用的物理内存之外的全部物理内存。
有5个数据结构主要关系到物理内存页的管理:页结构池,匿名内存池,自由表(freelist),页hash表,vnode页列表。