内存地址和分配

一、概念

Linux采用虚拟内存管理(Virtual Memory Management)机制(需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持)。

   内存地址分为虚拟地址(VA)和物理地址(PA)。

1.   物理地址(Physical Address,以下简称PA)

如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片接收,这称为物理地址(Physical Address,以下简称PA),如下图所示。

图 1. 物理地址


2.   虚拟地址(Virtual Address,以下简称VA)

如果处理器启用了MMU,CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将VA映射成PA,如下图所示。

图 2. 虚拟地址

l  虚拟地址空间大小:

   X86_32:4GiB

   X86_64:1TiB(redhat 仅支持256GiB)

l  查看进程占用地址空间情况

l  Proc files:
/proc/pid/status
/proc/pid/statm
l  Commands
#gnome-system-monitor   #gnome界面下查看
#pmap pid               #进程实际占用地址空间
#memusage progname  
#查看命令使用内存详细情况,需安装glibc-utils.i386和gd.i386包

 

二、虚拟地址空间管理

1.   虚拟地址空间和物理地址空间是独立的,虚拟地址必须被转换成物理地址。

#32位处理器的虚拟地址空间是4GB,而物理地址空间既可以大于也可以小于4GB

l  MMU将VA映射到PA是以页(Page)为单位的(32位处理器的页大小:4KB)。

l  物理内存中的页称为物理页面或者页帧(Page Frame)。

l  虚拟内存的哪个页面映射到物理内存的哪个页帧是通过页表(Page Table)(页表保存在物理内存中)来描述的

#例如,MMU可以通过一个映射项将VA的一页0xb7001000~0xb7001fff映射到PA的一页0x2000~0x2fff,如果CPU执行单元要访问虚拟地址0xb7001008,则实际访问到的物理地址是0x2008。


 

2.   每个进程都会占用一段线性、连续的虚拟地址空间,对应的物理地址空间通常是不连续的。

图3.不连续的PA可以映射为连续的VA

l  引入虚拟内存管理的优点

Ø  虚拟内存管理可以控制物理内存的访问权限。

Ø  虚拟内存管理最主要的作用是让每个进程有独立的地址空间。

Ø  VA到PA的映射会给分配和释放内存带来方便,物理地址不连续的几块内存可以映射成虚拟地址连续的一块内存。

Ø  一个系统如果同时运行着很多进程,为各进程分配的内存之和可能会大于实际可用的物理内存,虚拟内存管理使得这种情况下各进程仍然能够正常运行。

三、TLB(页表缓冲或旁路转换缓冲)

1.   概念

TLB:Translation lookaside buffer,即旁路转换缓冲,或称为页表缓冲;里面存放的是一些页表文件(虚拟地址到物理地址的转换表)。

TLB命中和TLB失败:如TLB中正好存放着所需的页表,则称为TLB命中(TLB Hit);如果TLB中没有所需的页表,则称为TLB失败(TLB Miss)。

TLB条目数:即页表条目数,Entry!

 

2.   TLB组成

在X86体系的CPU里边,一般都设有如下4组TLB:

l  第一组:缓存一般页表(4K字节页面)的指令页表缓存(Instruction-TLB);

l  第二组:缓存一般页表(4K字节页面)的数据页表缓存(Data-TLB);

l  第三组:缓存大尺寸页表(2M/4M字节页面)的指令页表缓存(Instruction-TLB);

l  第四组:缓存大尺寸页表(2M/4M字节页面)的数据页表缓存(Data-TLB);

[root@station10 proc]# x86info -c 
  #查询TLB信息还可用dmes和getconf -a|grep -i size等方法x86info v1.20.  Dave Jones 2001-2006
…
TLB info
 Instruction TLB:
 Instruction TLB:
 Data TLB: 4MB pages, 4-way associative, 32 entries
 L0 Data TLB:
 L0 Data TLB:
 Data TLB:
 64 byte prefetching.
…

 

3.   TLB原理

当CPU执行机构收到应用程序发来的虚拟地址后,首先到TLB中查找相应的页表数据,如果TLB中正好存放着所需的页表,则称为TLB命中(TLB Hit),接下来CPU再依次看TLB中页表所对应的物理内存地址中的数据是不是已经在一级、二级缓存里了,若没有则到内存中取相应地址所存放的数据。如果TLB中没有所需的页表,则称为TLB失败(TLB Miss),接下来就必须访问物理内存中存放的页表,同时更新TLB的页表数据。

既然说TLB是内存里存放的页表的缓存,那么它里边存放的数据实际上和内存页表区的数据是一致的,在内存的页表区里,每一条记录虚拟页面和物理页框对应关系的记录称之为一个页表条目(Entry),同样地,在TLB里边也缓存了同样大小的页表条目(Entry)。

 

 

4.   TLB调优

为提升交换速度,内核经常会刷新TLB,为增强TLB的性能,需给TLB划分空闲连续的物理页。

l  查询

[root@station9 ~]# cat /proc/buddyinfo
Node 0, zone     DMA    5     6   4   5   4   2  2  1  0  1  2
Node 0, zone   Normal   27    2   0   1   1   1  1  0  0  1  139
Node 0, zone  HighMem   105  356  190 118 99 41 16  9  2   2  617

 

l   手动设置hugepage大页(提升TLB命中率,减少PTE的访问时间)

Ø  1检查hugepagesize
[root@station9 ~]# cat /proc/meminfo |grep -i hugepagesize
Hugepagesize:     0 kB
#默认为0,其他查询方式有:x86info or dmesg

 

Ø  2开启hugepages功能

   修改/etc/sysctl.conf设置hugepages


 
 
[root@station9 ~]# vim /etc/sysctl.conf
vm.nr_hugepages = 20
              # vm.nr_hugepages=interger  #一个整数

或者修改内核参数(vim /etc/grub.conf)



 
 
   #hugepages=interger        #内核参数,一个整数

 
Ø  3如果应用程序有需要的话,要求挂载hugetlbfs
    [root@station9 ~]#mkdir /my-hugepages
    [root@station9 ~]#mount -t hugetlbfs none /my-hugepages
    #重启生效需写入到/etc/fstab
    #mmap system call必须挂载hugetlbfs
#shmat和shmgt system call无需挂载hugetlbfs


 

l  查看system calls

[root@station9 ~]#strace -o /tmp/outfile elinks -dump http://192.168.32.38
[root@station9 ~]#grep mmap /tmp/outfile
    [root@station9 ~]#strace -c elinks -dump http://192.168.32.38
#查询汇总
#通过starace查询系统call可以审查内容查询、文件系统的故障、查询IO故障等


netsword 51CTO博客,原文链接:http://blog.51cto.com/netsword/647547