运行时系统是如何将存储器空间划分为更可管理的单元,以存放不同的程序对象(program object),即程序数据、指令和控制信息。可以用各种机制来分配和管理程序不同部分的存储。这种管理完全是在虚拟地址空间里完成的。
虚拟存储:
        虚拟存储是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占地占用物理内存。
        每个进程看到的是一致且连续的存储空间,称为虚拟地址空间。在 Linux 中,地址空间最上面的区域是为操作系统中的代码和数据保留的,这对所有进程来说都是一样的。地址空间的底部区域存放用户进程定义的代码和数据。进程由执行的指令代码、数据和堆栈区组成。程中的代码和数据部分分别对应一个执行文件中的代码段、数据段。每个进程只能执行自己的代码和访问自己的数据及堆栈区。进程之间的通信需要通过系统调用来
    每个进程看到的虚拟地址空间由段构成,每个段都有专门的功能。
    1、程序代码和数据段:
    2、堆段:
    3、共享库段:
    4、栈段:
    5、内核虚拟虚拟存储器:

      对于应用进程来讲,在申请内存时使用的是线***地址。并且应用程序的访问对像都是虚拟地址。CPU在程序的指令控制下完成一系列操作,最终实现特定目标或解决特定问题。

      CPU加载程序的一条指令,CPU获得了该指令的虚拟地址(虚拟存储器的”程序和数据段“),而使用虚拟地址寻址是无法加载该指令。所以就要使用到地址翻译,把虚拟地址转换为物理物理内存的地址。CPU 使用物理地址才可以从存储器中成功加载指令。所以,一个进程运行时使用到的指令和数据映射到物理内存的页面速度,很大程序地影响到了进程运行的效率。使用下述方法就可以查看一个进程的虚拟地址的分布状况和它的常驻物理内存的大小。

 [root@node2 ~]# pmap -x 15920
15920:   nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
Address   Kbytes     RSS   Dirty Mode   Mapping
00110000     588       0       0 r-x--  libkrb5.so.3.3
001a3000      12      12      12 rwx--  libkrb5.so.3.3
002ca000     104      24       0 r-x--  ld-2.5.so
002e4000       4       4       4 r-x--  ld-2.5.so
002e5000       4       4       4 rwx--  ld-2.5.so
002ed000    1276     108       0 r-x--  libc-2.5.so
0042c000       4       0       0 --x--  libc-2.5.so
0042d000       8       8       8 r-x--  libc-2.5.so
0042f000       4       4       4 rwx--  libc-2.5.so
00430000      12      12      12 rwx--    [ anon ]
...
08047000     432      80       0 r-x--  nginx
080b3000      40      40      36 rw---  nginx
080bd000      40      12      12 rw---    [ anon ]
09fb6000     132     124     124 rw---    [ anon ]
b7fd9000      20      20      20 rw---    [ anon ]
b7fe7000       4       0       0 rw-s-  zero (deleted)
bfde8000      84      12      12 rw---    [ stack ]
-------- ------- ------- ------- -------
total kB    5740       -       -       -
[root@node2 ~]# cat /proc/15920/status
Name:   nginx
...
VmPeak:     5740 kB
VmSize:     5740 kB
VmLck:         0 kB
VmHWM:       712 kB
VmRSS:       712 kB
VmData:      436 kB
VmStk:        84 kB
VmExe:       432 kB
VmLib:      4536 kB
VmPTE:        40 kB
StaBrk: 09fb6000 kB
Brk:    09fd7000 kB
StaStk: bfdfbd00 kB
ExecLim:        080b3000
Threads:        1
...

       Linux 内核的内存管理程序采用了分页管理方式。选用页目录和页表结构处理内核中其它部分代码对内存的申请和释放操作。
       虚拟地址通过段管理机制首先变成一种中间地址形式--CPU 32 位的线***地址,然后使用分页管理机制将此线***地址映射到物理地址。使用页表(page table)来描述线***地址的页(page)与物理内存的页面(pagc frame)的对应关系。
      Linux 完成应用程序代码/数据的虚拟地址到物理地址的转换,是由CPU中的一个存储管理单元(Memory Management Unit,MMU)通过该表(page table)来计算出虚拟地址与物理内存地址的映射关系来实现的。

       为了减少地址转换所需要的总线周期数量(加速虚拟地址到物理地址的转换过程),把MMU计算的结果存放在处理器的页高速缓冲器件中,该缓冲器件被称转换查找缓冲区(Translation LookasideBuffer, TLB).TLB 相当于页表的专用高速缓存,其中缓存(正在运行)进程最近用到的几个页号和页面号的对应关系,所以TLB的每项包括逻辑页号(称为键号)和页面号(称为值)两部分。但是 TLB 能够缓存的条目的数据是有限的,不能缓存 MMU 每次计算的结果。所以系统会根据某种算法定期的从 TLB 中把一些缓存数据清理掉。所以说并不是每次都可以从 TLB 中快速得到虚拟地址到物理地址的映射的。这就涉及到了 TLB 缓存命中率。提高TLB缓存命中率,就可以加速虚拟地址到物理地址的转换速度。TLB 的缓存条目是固定的,可以使用下述方法查看:

[root@node2 ~]# x86info -c
...
TLB info
 Data TLB: 4KB pages, 4-way associative, 64 entries
 64 byte prefetching.
 ...

说明:
   系统使用的页面大小是4KB.

使用大页面来提高 TLB 的命中率。

[root@node2 ~]# cat /proc/meminfo | grep -i hugepage
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     4096 kB

说明:
    HugePages_Total的值为0表示没有开启大页面功能。
    Hugepagesize 表示能使用的内存大页面为:4M 大小。


       为了让更大限度地利用物理内存,把物理内存中一些不常用的页面交换到别的存储器中。如:swap 分区。腾出更多的物理内存空间给别的进程使用。
         如果一个进程的页面数据被交互到swap分区上了,内核重新调度到该进程运行时,要使用到被交换到swap分区的页面数据不在物理内存的页面上(该数据原来的物理地址)。CPU 会产生一个缺页异常中断,此时内核的缺页异常处理程序又把执行该页面数据从swap分区中加载到内存中来,使用应用程序能够继续执行下去。

      Linux 的内存由物理内存(RAM)和交互分区(swap)组成的。但是swap 分区的速度是远远比物理内存(RAM)的速度慢的。所以进程的页面数据的交换必然会影响到进程的执行效率的。这就需要一种办法来根据我们系统上的应用来限制进程是对交换分区swap的使用. ------> 这是一种缺页异常 page fault

先看一下系统上内存的使用情况:

[root@node2 ~]# free
             total       used       free     shared    buffers     cached
Mem:        255412     251620       3792          0      28404     136540
-/+ buffers/cache:      86676     168736
Swap:       128512          0     128512

说明:
    系统上内核可以直接为应用程序申请的内存大小为:3792KB. 约3M. 所有有新的进程要申请大于3M的内存,系统就会释放 buffers或cached所占据的内存。
    也可以手动来释放 buffers 或 cached 所占据的内存。 echo value > /proc/sys/vm/drop_caches;
    应用程序可以使用的内存还有:168736KB。约164M.

监测各种内存页面的申请和释放的情况

root@node2 ~]# sar -R 1  80
Linux 2.6.18-194.el5 (node2.a.org)      06/15/2014
05:28:30 AM   frmpg/s   bufpg/s   campg/s
05:28:31 AM    -61.22     52.04     -2.04
05:28:32 AM    -82.19     29.45     -0.68
05:28:34 AM    -26.79      2.68      0.89
05:28:35 AM      0.00      0.00      0.00
05:28:36 AM      0.00      0.00      0.00

Linux 通过 /proc 接口提供了几个内核参数
1、控制使用swap的倾向***:

root@node2 ~]# cat /proc/sys/vm/swappiness
60

 

说明:
    vm.swappiness的取值范围: 0~100
    ( 匿名页(页缓存page cache)的百分比 + swappiness的百分比 ) 大于 100% 的话,就开始使用swap分区了。

2、控制内存的使用。如:只使用物理内存不使用swap分区、怎样使用swap分区

[root@node2 ~]# cat /proc/sys/vm/overcommit_memory
0

说明:
    overcommit_memory 有三个(0|1|2)取值不同的值表示不同意义:
    0      表示启发式过量。
    1      表示总是过量。
    2      可以超出指定的百分比。该值要结合 vm.overcommit_ratio参数使用。
   

3、指定过量使用内存的百分比。

[root@node2 ~]# cat /proc/sys/vm/overcommit_ratio
50

        系统运行一个应用程序时并不是把该进程所有的数据代码一次***全部加载到物理内存当中的,因为磁盘的IO速度要远远比内存的速度慢得多,为了加速进程的启动速度,Linux使用一种称为“需要加载技术(Load on demand)”.意思是运行进程时,只有当使用到代码和数据时,才从文件系统(也就是从磁盘)中把代码和数据加载到物理内存中来。
        这有一个问题:CPU在执行过程中,运行到未加载的代码页或代码指令需要访问还未加载的数据,那么CPU这时候会报告一个缺页异常中断。此时,内核就会启用缺页中断处理
程序把对应页面从磁盘中加载到物理内存中来。并映射到进程逻辑地址中指定指定的页面位置处。当内核的异常处理程序返回后,CPU就会重新执行引起异常的指令。这样执行程序能够得以继续往下执行。------> 这是另个一种缺页异常page fault。

页请求异常导致的缺页异常分为两类:
                                                              1、major fault.
                                                              2、minor fault.


每秒钟的数据报告。

[root@node2 ~]# sar -B 1 80
Linux 2.6.18-194.el5 (node2.a.org)      06/15/2014
05:24:48 AM  pgpgin/s pgpgout/s   fault/s  majflt/s
05:24:49 AM      0.00      0.00     52.53      0.00
05:24:50 AM      0.00      0.00     23.71      0.00
05:24:51 AM      0.00      0.00     11.88      0.00
05:24:52 AM      0.00      0.00     12.24      0.00

说明:
    fault:       page faults (major + minor)
    majflt:      major  faults

监测指定进程的的缺页异常

[root@node2 ~]#  watch -n 1 'ps axo pid,comm,min_flt,maj_flt,vsize,rss | grep httpd'
Every 1.0s: ps axo pid,comm,min_flt,maj_flt,vsize,r...  Sun Jun 15 05:34:29 2014
27833 httpd             1106      3  35772 10208
27836 httpd             3019     65  38060 12060
27837 httpd              195      0  35772  8532
27838 httpd             3137     80  37532 11740
27839 httpd              195      0  35772  8532
27840 httpd              195      0  35772  8532
28109 httpd              237      0  35772  8696