Solaris内存管理的一些基本原理
首先需要对Solairs的内存管理有一个基本的了解。Solaris内存管理简单来说就是“虚拟内存管理”模型。(注:现代OS差不多都是虚拟内存管理,包括Windows,Linux)虚拟内存的定义是:
虚拟内存的定义是基于对地址空间的重定义的,即把地址空间定义为连续的虚拟内存地址,以借此欺骗程序,使它们以为自己正在使用一大块的连续地址。(参见:虚拟内存- 维基百科)
虚拟内存也就是为了编程的方便,而为应用程序假象一个地址空间。就是对于64bit的Solaris来说,虚拟地址空间就是2^64Byte,基本就看成 无穷大吧。;对于32位的操作系统就是4G(如果内核空间独立的话,可能就是2G或者3G,如WindowsXP)。虚拟内存和实际物理内存的映射关系通 过CPU的MMU(内存管理单元)来完成。
首先,通过在root权限下执行
# echo ::memstat |mdb -k
Page Summary Pages MB %Tot
------------ ---------------- ---------------- ----
Kernel 49709 388 2%
Anon 927367 7245 46%
Exec and libs 5186 40 0%
Page cache 212025 1656 11%
Free (cachelist) 787615 6153 39%
Free (freelist) 31964 249 2%
Total 2013866 15733
# echo ::memstat |mdb -k
Page Summary Pages MB %Tot
------------ ---------------- ---------------- ----
Kernel 70542 551 4%
Anon 950567 7426 47%
Exec and libs 5965 46 0%
Page cache 6219 48 0%
Free (cachelist) 978159 7641 49%
Free (freelist) 2414 18 0%
Total 2013866 15733
这里给出了“物理内存”的分配细节
- Kernel:内核占用的内存。这部分内核占用的内存一般为了保证性能是不允许被换页的。
- Anon(Anonymous匿名内存):简单的理解就是用户进程分配给自己专有的内存。准确的说应该是包括用户进程堆空间、栈空间和copy-on-write页面、共享内存映射和小的内核辅助内存,诸如代表用户进程的lwp线程栈空间。这部分内存常常需要需要进行写操作的,导致换页时候,也必须完成回写操作,使得这部分内存的换页成本非常高。----这又牵涉到一个Copy-on-write - Wikipedia的概念。
- Exec and libs:为库函数所分配的内存。差不多算是只读内存,库函数显然没有必要被修改,这部分内存在需要的时候可以被直接扔掉。
- Page Cache:不在缓存列表上的页面缓存。可以这样理解,系统刚开始运行时,保留一部分物理内存作为文件系统缓存,但初始时并没有被任何文件系统内容使用。一般来说系统运行一段时间后,这部分就差不多变成0了。
- Free(cachelist): 在空闲列表中的页面缓存大小。差不多可以认为是已经分配的文件系统缓存。(Solaris 8不认为这属于vmstat中的空闲内存,因此常常看到空闲内存为0,但是系统一样跑的很好;在Solaris9中把这部分内存也作为vmstat中的空 闲内存对待)
- Free(freelist):真正空闲的内存大小。这是与任何文件或者进程没有联系的正真的空闲内存。
上面各种内存的顺序差不多是按照 被“换页”成本进行排序的,越往上,换页成本越高。
$ pmap -x 15565
15565: oracleora10g (LOCAL=NO)
Address Kbytes RSS Anon Locked Mode Mapped File
0000000100000000 100128 99208 - - r-x-- oracle
00000001062C6000 808 688 176 - rwx-- oracle
0000000106390000 936 920 920 - rwx-- [ heap ]
......
FFFFFFFF7DB06000 56 40 40 - rwx-- libclsra10.so
FFFFFFFF7DB14000 8 - - - rwx-- libclsra10.so
FFFFFFFF7DB70000 64 48 48 - rw--- [ anon ]
FFFFFFFF7DB80000 64 48 48 - rw--- [ anon ]
......
FFFFFFFF7DC00000 9256 8200 - - r-x-- libjox10.so
......
FFFFFFFF7EB00000 8 8 8 - rwx-- [ anon ]
......
FFFFFFFF7FFF0000 64 64 64 - rw--- [ stack ]
---------------- ---------- ---------- ---------- ----------
total Kb 20243504 20234792 3616 20119600
再来看看,对于一个应用程序来说,它的内存分配情况。举例说明,比如,为Oracle启动分配20G(也可以是200G)的内存。
- 虚拟内存:在分配内存时候可以不必理会物理内存有多少,只要满足两个条件:1、交换分区(swap)空间+物理内存大于20G;2、不能超过操作系统的地址空间,如64位系统就是2^64字节;从上面的例子看,为这个Oracle直接分配的就是就是分配的20243504Kbytes虚拟内存
- 物理内存:由 于这20G的内存,有可能一次也不会被访问到(假设这Oracle是你自己开发的,你分配了一个20G的大数组,却忘了使用它----虽然愚蠢,但也不是 不可以)。因此OS比较聪明的做法是没必要一次性地把这20G都装入物理内存,而是在确实需要访问的时候再分次分批的装入。装入物理内存的部分就是“驻留 内存”。从上面的例子看,这个Oracle所占用的物理内存就是分配的RSS20234792。
- 匿名内存:一般你的系统上有好几十个Oracle进程,显然不可能每一个Oracle都独立占用20G内存,事实上从上面例子看只有Anon所占用的3616K内存是这个Oracle所独有的,20243504-3616K都是共享的部分。
- 缺页扫描阶段:前 提是物理内存不足20G,这时候就利用上了swap分区。如果发生需要的数据不在内存,就会进行“缺页扫描”,看看能否把啥内存换出到磁盘上(swap out)。Solaris有“慢扫”和“快扫”两种,在缺页情况不严重的时候,一秒钟扫“页表”几十次;如果缺页情况严重,一秒钟就扫描“页表”几千次。 当然在“快速扫描”的情况下,系统性能基本上就不能保证了。
- 换页阶段:这个大家都理解了,这里就不说了。
判定Solaris系统内存是否够用的方法
1、prstat -mL查看进程等待内存的时间百分比(DFL值)
$ prstat -mL
PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID
15931 oracle 12 4.8 0.0 0.0 0.0 0.0 83 0.0 237 0 13K 0 oracle/1
15929 oracle 5.9 7.8 0.0 0.0 0.0 0.0 88 0.0 205 19 11K 0 oracle/1
15927 oracle 8.3 5.0 0.0 0.0 0.0 0.0 88 0.0 158 0 9K 0 oracle/1
......
DFL表示花费在等待内存的时间百分比。上述DFL=0表示没有发生换页情况,内存够用。
2、vmstat查看空闲内存(free值)和缺页扫描频率(sr值)
bash-2.05$ vmstat 1
kthr memory page disk faults cpu
r b w swap free re mf pi po fr de sr m1 m2 m3 m4 in sy cs us sy id
0 0 0 26057344 7601120 219 2127 31 7 7 0 0 0 0 0 0 4560 6583 2744 7 3 90
0 0 0 25980920 6367384 3 9 0 0 0 0 0 0 0 0 0 749 452 841 0 0 100
0 0 0 25980920 6367384 0 0 0 0 0 0 0 0 0 0 0 581 297 710 0 0 100
......
free表示空闲内存为 6367384,关键的是sr=0,表示缺页扫描频率为0,也就是不发生缺页扫描。
3
# echo hardswap/D|mdb -k
hardswap:
hardswap: 0
硬交换为0,当然是内存够用。