您的位置:首页 > 运维架构 > Linux

linux内存基础知识和相关调优方案

2016-01-11 18:15 459 查看
内存是计算机中重要的部件之中的一个。它是与CPU进行沟通的桥梁。

计算机中全部程序的执行都是在内存中进行的。因此内存的性能对计算机的影响很大。内存作用是用于临时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。仅仅要计算机在执行中。CPU就会把须要运算的数据调到内存中进行运算。当运算完毕后CPU再将结果传送出来。内存的执行也决定了计算机的稳定执行。对于整个操作系统来说,内存可能是最麻烦的的设备。而其性能的好坏直接影响着整个操作系统。

我们知道CPU是不能与硬盘打交道的。仅仅有数据被加载到内存中才干够被CPU调用。cpu在訪问内存的时候须要先像内存监控程序请求,由监控程序控制和分配内存的读写请求。这个监控程序叫做MMU(内存管理单元)。以下以32位系统来说明内存的訪问过程:

32位的系统上每个进程在訪问内存的时候,每个进程都当做自己有4个G的内存空间可用。这叫虚拟内存(地址),虚拟内存转化成物理内存是通过MMU来完毕的。

为了可以从线性地址转换成物理地址。须要page table(页表)的内存空间,page table要载入到MMU上。

为了完毕线性地址到物理地址的映射,假设依照1个字节1个字节映射的话,须要一张很大的表,这样的转换关系会很的复杂。因此把内存空间又划分成了第二种存储单元格式。通常为4K。在不同的硬件平台上,它们的大小通常是不一样的。像x86 32位的有4k的页。而64位的有4k页,2M页,4M页。8M页等等。默认都是4k的。

每个进程一般而言都有自己的页路径和页表映射机制。无论那一个页表都是由内核载入的。每个进程仅仅能看到自己的线性地址空间,想要添加新的内存的时候,仅仅能在自己的线性地址空间中申请。而且申请后一定是通过操作系统的内核映射到物理地址空间中去找那么一段空间,而且告诉线性地址空间准备好了,可以訪问。而且在page
table中添加一条映射关系,于是就能够訪问物理内存了。这样的叫做内存分配。

可是新的申请一定是通过操作的内核到物理内存中去找那么一段空间,而且告诉线性地址空间好了,能够建设映射关系。终于page table建立映射关系。

下图反映了上述描写叙述过程的大体情况。能够看到每个用户程序都会有自己的页表。而且映射到相应的主存储器上去。



依据上述文字和图表的描写叙述能够发现2个问题:

1.每一个进程假设须要訪问内存的时候都须要去查找page table的话,势必会造成server的性能底下

2.假设主存储器的内存满了以后,应用程序还须要调用内存的时候怎么办

对于第一个问题。我们就须要借助TLB(Translation Lookaside Buffer)翻译后备缓冲器。TLB是一个内存管理单元,它能够用于改进虚拟地址到物理地址转换速度的缓存。这样每次在查找page table的时候就能够先去TLB中查找对应的页表数据。假设有就直接返回,没有再去查找page table,并把查找到的结果缓存中TLB中。TLB尽管攻克了缓存的功能。可是在那么page table中查找映射关系仍然非常慢,所以又有了page table的分级文件夹。page table能够分为1级文件夹,2级文件夹和偏移量

可是一个进程在执行的时候要频繁的打开文件,关闭文件。这就意味着要频繁的申请内存和释放内存。有些能够在内存中缓存数据的那些进程,他们对内存的分配和回收很多其它。那么每一次分配都会在页表中建立一个相应项。

所以,就算内存的速度非常快,大量频繁的同一时间分配和释放内存,依旧会减少server的总体性能。

当然内存空间不够用的时候,我们称为oom(out of memory,内存耗尽)。当内存耗尽的时候,。整个操作系统挂了。这样的情况下我们能够考虑交换分区,交换分区毕竟是由硬盘虚拟出来的内存,所以其性能与真正的内存相比,差了非常多。所以要尽力避免使用交换分区。有物理内存空间的时候尽量保证所有使用物理内存。cpu不管怎样是不能给交换内存打交道的,它也仅仅能给物理内存打交道。能寻址的空间也仅仅能是物理内存。所以当真正物理内存空间不够用的时候,会通过LRU算法把当中近期最少使用的内存放到交换内存中去,这样物理内存中的那段空间就能够供新的程序使用了。可是这样会引发另外的一个问题,即原来的进程通过page
table寻找的时候,那一段空间的数据已经不属于它了。所以此刻cpu发送通知或者异常告诉这个程序,这个地址空间已不属于它。这个时候可能会出现2种情况:

1.物理内存有可用的空间可用:这个时候cpu会依据曾经的转换策略会把交换分区中的那段内存又一次送到物理内存中去,可是转换过来的空间地址不一定会是曾经的那一段空间地址,由于曾经的那一段空间地址可能已经被别人使用了。

2.物理内存没有可用的空间可用:这个时候依旧会使用LRU算发把当前物理地址空间上近期最少使用的空间地址转换到交换内存中去,并把当前进程须要的这断在交换空间中的内存送到物理内存空间中去,而且又一次建立映射关系。

上述通知或者异常出现的情况,通常叫做缺页异常。缺页异常也分为大异常和小异常两种。大异常就是訪问的数据内存中没有。不的不去硬盘上载入,不管是从交换内存中还是直接从磁盘的某个文件系统上。反正须要从硬盘上去载入,这样的异常载入须要非常长时间。小异常就是进程之间通过共享内存。第二个进程訪问的时候。查看本地的内存映射表没有,可是其他进程已经拥有了这个内存页。所以能够直接映射。这样的异常载入须要的时间一般非常短。

在操作系统开机的时候。每个io设备都会像cpu申请一些列的随机port。这样的port叫做ioport。

在IBM PC体系结构中,I/O地址空间一共提供了65,536个8位的I/Oport。正是这些ioport的存在。cpu能够与io设备进行读写交互的过程。

在执行读写操作时,CPU使用地址总线选择所请求的I/Oport,使用数据总线在CPU寄存器和port之间传送数据。

I/Oport还能够被映射到物理地址空间:因此,处理器和I/O设备之间的通信就能够直接使用对内存进行操作的汇编语言指令(比如,mov、and、or等等)。现代的硬件设备更倾向于映射I/O,由于这样处理的速度较快,并能够和DMA结合起来使用。这样io在和内存传数据的时候就不须要通过cpu。cpu把总线的控制权交给DMA。每次io传数据的时候就调用DMA一次,就把cpu给解放了出来。当传输数据完了以后。DMA通知给cpu中断一次。

DMA在执行的时候对整个总线有控制权限。当cpu发现有其他进程须要使用总线的时候。二者就会产生争用。这个时候,在总线控制权的使用上。CPU和DMA具有相等的权限。仅仅要CPU托付给了DMA。就不能任意的收回这个托付。就要等待DMA的用完。

假设没有其他进程能够执行,或者其他进程执行的时间很短。这个时候CPU发现我们的IO仍然没有完毕,那就意味着。CPU仅仅能等待IO了。CPU在时间分配里面有个iowait的值,就是CPU在等待IO花费的时间。有些是在同步调用过程中,CPU必需要等待IO的完毕;否者CPU能够释放IO的传输在背后自己主动完毕,CPU自己去处理其他的事情。

等硬盘传输数据完毕以后,硬盘仅仅需要像CPU发起一个通知就可以。CPU外围有一种设备,这个设备叫做可编程中断控制器。每个硬件设备为了给CPU通信。在刚开机的时候,在BIOS实现检測的时候,这个设备就要到可编程中断控制器上去注冊一个所谓的中断号。那么这个号码就归这个硬件使用了。当前主机上可能有多个硬件,每个硬件都有自己的号码,CPU在收到中断号以后,就能够通过中断相量表查找到那个硬件设备进行中断。而且就由相应的IOport过来处理了。

CPU正在运行其他进程,当一个中断请求发过来的时候,CPU会马上终止当前正在处理的进程,而去处理中断。

当前CPU挂起当前正在处理的进程,转而去运行中断的过程。也叫做中断切换。仅仅只是,这样的切换在量级别上比进程切换要低一些,并且不论什么中断的优先级通常比不论什么进程也要高。由于我们指的是硬件中断。中断还分为上半部和下半部,一般而言,上半部就是CPU在处理的时候,把它接进来,放到内存中,假设这个事情不是特别紧急(CPU或者内核会自己推断),因此在这样的情况下。CPU回到现场继续运行刚才挂起的进程,当这个进程处理完了,再回过头来运行中断的下半部分。

在32位系统中,我们的内存(线性地址)地址空间中。一般而言。低地址空间有一个G是给内核使用的,上面3个G是给进程使用的。

可是应该明确,事实上在内核内存其中,再往下,不是直接这样划分的。

32位系统和64位系统可能不一样(物理地址),在32位系统中。最低端有那么10多M的空间是给DMA使用的。DNA的总线宽度是非常小的。可能仅仅有几位,所以寻址能力非常有限,訪问的内存空间也就非常有限。假设DMA须要复制数据,并且自己可以寻址物理内存,还可以把数据直接壮哉进内存中去,那么就必须保证DMA可以寻址那段内存才行。寻址的前提就是把最低地址断M。DA的寻址范围内的那一段给了DMA。

所以站在这个角度来说,我们的内存管理是分区域的。

在32位系统上,16M的内存空间给了ZONE_DMA(DMA使用的物理地址空间);从16M到896M给了ZONE_NORMAL(正常物理地址空间),对于Linux操作系统来说,是内核能够直接訪问的地址空间。从896M到1G这断空间叫做"Reserved"(预留的物理地址空间);从1G到4G的这段物理地址空间中,我们的内核是不能直接訪问的。要想訪问必须把其中的一段内容映射到Reserved来,在Reserved中保留出那一段内存的地址编码,我们内核才干上去訪问,所以内核不直接訪问大于1G的物理地址空间。所以在32位系统上,它訪问内存其中的数据,中间是须要一个额外步骤的。

在64位系统上,ZONE_DAM给了低端的1G地址空间,这个时候DMA的寻址能力被大大加强了。ZONE_DAM32能够使用4G的空间;而大于1G以上给划分了ZONE_NORMAL,这段空间都能够被内核直接訪问。所以在64位上。内核訪问大于1G的内存地址,就不须要额外的步骤了,效率和性能上也大大添加。这也就是为什么要使用64位系统的原因。上述过程的描写叙述图例如以下:



在如今的PC架构上。AMD,INTER都支持一种机制,叫做PEA(物理地址扩展)。所谓PAE。

指的是在32位系统的地址总线上。又扩展了4位。使得32位系统上的地址空间可以达到64G。当然在32为系统上。无论你的物理内存有多大,单个进程所使用的空间是无法扩展的。由于在32位的系统上,线性地址空间仅仅有4个G。而单个进程可以识别的訪问也仅仅有3个G。

linux的虚拟内存子系统包括了下面几个功能模块:

slab allocator,zoned buddy allocator,MMU,kswapd,bdflush

slab allocator叫做slab分配器

buddy allocator又叫做buddy system,叫做伙伴系统。也是一种内存分配器

buddy system是工作在MMU之上的,而slab allocator又是工作在buddy system之上的。



系统中的内存频繁分配和回收势必会造成内存碎片。为了尽量的避免内存碎片,buddy system在实现内存分配时。它事先可以将内存先划分成大小像似的多种不同的单位。分配出去的时候尽可能找那个最适合的那段内存空间向外分配,而且假设某一进程的内存空间释放以后,它可以将多个离散的,相邻的小内存空间合并成一段更大的连续区域。所以分配的时候。尽可能找最适合的缝隙进行分配,而终于可以把多个进程所释放的地址空间合并起来成为一段连续的空间,而且没有划分页。进程的有些所须要的内存空间是不同意分页的,所以说假设没有一大段的连续内存空间,这段信息将无法存储。

所以内存在分配的时候尽可能找最佳空间像外分配,而且回收的时候可以合并内存成连续的大内存空间。这就是buddy
system的意义,用于避免内存外碎片。

所谓外碎片。就是指内存中有非常多页都不连续。buddy allocator仅仅是用来分配页面或者非页面那些连续的空间的申请。一般这样的空间级别都比較大。但有些时候我们须要的空间都比較小。比方打开一个文件。訪问INODE的时候。

这样的时候有可能放在一个页面中,可是这个页中就仅仅存这个INODE,就会造成空间的大大浪费。

所以对于这些信息的存储,尽管有可能也是将数据放在页中,可是页中肯定不仅仅是为了存这一个数据,有可能存多个数据。

那么怎样高速的存储下来呢?每个INODE就是一个特殊的数据结构。它里面有各种信息,所以我们叫做特殊的数据结构。

那我们存储的时候,不仅要存储数据,还要存储它的结构,而这样的数据是小于页面的。

想要达到高速存储,这就是slab
allocator存在的意义了。它可以实现自己去申请几个页面。把这几个页面划分成独特的内部适于存储某种对象的数据结构。直接给划分好。结构也给存好了,当须要存储INODE的时候,把INODE信息填写进去就行了。结构都事先给分配好了。当一个文件关闭以后。它的INODE也要清除出去了。

slab allocator还能把它清除出去的那些INODE收回回来供其他进程打开文件时继续使用。这就是为了避免内存内碎片,完毕小片内存分布的。

当我们实现buddy system在内存分配空间时。假设物理内存空间不够用,有可能会用到交换内存。

kswapd就是实现swap out和swap in的。将数据放到swap上和从swap上将数据载回到内存中。

当然更应该明确的是,假设某一个进程改动了数据,这个数据终于是要从内存上填到磁盘中去的。

由于进程訪问的数据都是在内存中完毕的,这些数据终于要写到附存上去,才干完毕数据的永久存储。怎么进行这个写操作,就是靠pdflush来完毕的。我们一往内存中写数据,并非立即就写入到磁盘中的。由于这种性能太差了。这个过程是异步的。而不是同步的。

由我们内核定期的将那些已经保存了的数据给它同步到磁盘上去。pdflush是一个内核的线程,通常一块硬盘有一个。监控着当前内存空间中有那些数据(通常叫做脏页)已经被改动过了,尚且未同步到磁盘中的数据给存储到磁盘中去。当然它并非一定要主动监控,假设物理内存中的脏页已经达到了一个百分比,它也会去主动同步数据的。

物理内存中那些被改动了的数据是不能交换的,必需要往磁盘中写。由于交换可能会带来一些故障。所以,我们可以交换到交换内存中的数据,一定是没有被改动过的数据,改动过的,要腾出来,就仅仅能往硬盘中写。

有了内存的基础知识概念以后。以下就能够来看一些关于内存的经常使用调优方案了:

一.与hugepage相关的调优參数

cat /proc/zoneinfo 能够查看当前操作系统上的内存区段的切割情况

HugePage:大页面

在centos64位的系统上不仅支持大页面,还支持透明大页(THP,transparent huge page)

透明大页简单来说就是对匿名内存段的使用。它可以不须要不论什么用户的參与。自己主动的由操作系统在背后使用大页面来管理匿名内存段。那一段内存是匿名内存段呢?RSS减去共享内存就是匿名内存段。

透明大页对于CENTOS64位的系统来说支持两种大小。一个是2M,一个是1G。1G在TB内存级的使用上通常非常有效。

在几十G。上百G的内存中,2M一般是不错的选择。通常仅仅有物理内存大于4G的时候,透明大页的机制才会启动起来。透明大页通常情况下。是系统在背后悄悄使用的,为什么叫做透明。是由于用户是不须要參与的。

在/proc/zoneinfo下的 nr_anon_transparent_hugepages这个參数能够看到透明大页的使用情况,通常一个页面是2M。

在/proc/meminfo下的:

AnonHugePages:能够看到透明页的总大小

Hugepagesize:大页的大小。

HugePages_Total: 大页的总数

HugePages_Free: 剩余大页的总数

HugePages_Rsvd:预留的大页总数

HugePages_Total是用户自己指定的,而非透明大页。

使用vm.nr_hugepages = n能够手动指定大页的个数。一般来说,我们能够自己手动定义把他们当做共享内存空间来使用来挂载。直接把他当做内存中的分区挂载到某个文件系统的文件夹上。

用法例如以下:

mkdir /hugepages

mount -t hugetlbfs none /hugepages

然后就能够把hugepages当做内存磁盘来使用了。

当然,平时的时候是不须要我们自己指定的,比方说像mysqlserver,在mysqlserver上有一个变量,把那个变量其中定义要使用透明大页。它就会自己主动使用了。

二.与buffer和cache的相关调优參数

/proc/sys/vm/drop_caches能够手动强制释放buffer和cache,其接受3个參数

假设为1:就释放全部的pagecache页缓存

假设为2:就释放dentries和inode的缓存

假设为3:就释放pagecache,dentries和inode的缓存

buffer和cache中的缓存分为两大类:

1.pagecache:用来缓存页数据的。通常缓存的是文件数据,打开的文件内容

2.buffers:缓存的是文件的元数据(inode和dentries),有时候也用来缓存写请求的

echo 1 > /proc/sys/vm/drop_caches 就释放上面的第一条

echo 2 > /proc/sys/vm/drop_caches 就释放上面的第二条

echo 3 > /proc/sys/vm/drop_caches 就释放上面两条之和

三.与交换内存的相关调优參数

/proc/sys/vm/swappiness表示内核用多大的倾向去使用交换内存

值越大就越倾向于使用交换内存,值越小越不倾向使用交换内存(可是这并不代表不能使用交换内存),默认值为60。取值范围为0-100。

在server上建议把这个值调小,甚至为0。

一般而言,当我们眼下已经映射到页表中的内存百分比(也就说我们物理内存中的百分比有多少被页表使用了)+vm.swappiness的值大于等于100的时候,就会開始启用交换内存。

交换内存的使用建议:

1.在运行批处理计算(科学计算)的server上,能够把它设置的相对偏大

2.在数据库server上。能够设置为小于等于1G,在数据库server应该劲量避免使用交换内存

3.在应用server上,能够设置为RAM*0.5,当然这个是理论值

假设不的不使用交换内存。应该把交换内存放到最靠外的磁道分区上,由于最外边的磁盘的訪问速度最快。所以假设有多块硬盘。能够把每块硬盘的最外层的磁道拿一小部分出来作为交换分区。

交换分区能够定义优先级。因此把这些硬盘的交换内存的优先级设置为一样。能够实现负载均衡的效果。

定义交换分区优先级的方法为编辑/etc/fstab:

/dev/sda1 swap
swap pri=5 0 0

/dev/sdb1 swap
swap pri=5 0 0

/dev/sdc1 swap
swap pri=5 0 0

/dev/sdd1 swap
swap pri=5 0 0

四.内存耗尽时候的相关调优參数

当Linux内存耗尽的时候,它会杀死那些占用内存最多的进程,下面三种情况会杀死进程:

1.全部的进程都是活动进程,这个时候想交换出去都没有空暇的进程

2.没有可用的page页在ZONE_NORMAL中

3.有其他新进程启动,申请内存空间的时候,要找一个空暇内存给做映射。可是这个时候找不到了

一旦内存耗尽的时候,操作系统就会启用oom-kill机制。

在/proc/PID/文件夹下有一个文件叫做oom_score,就是用来指定oom的评分的,就是坏蛋指数。

假设要手动启用oom-kill机制的话。仅仅须要运行echo f>/proc/sysrq-trigger就可以。它会自己主动杀掉我们指定的坏蛋指数评分最高的那个进程

能够通过echo n > /proc/PID/oom_adj来调整一个进程的坏蛋评分指数。

终于的评分指数就是2的oom_adj的值的N次方。假如我们的一个进程的oom_adj的值是5,那么它的坏蛋评分指数就是2的5次方。

假设想禁止oom-kill功能的使用能够使用vm.panic_on_oom=1就可以。

五.与容量有关的内存调优參数:

overcommit_memory,可用參数有3个,规定是否可以过量使用内存:

0:默认设置,内核运行启示式的过量使用处理

1:内核运行无内存的过量使用处理。使用这个值会增大内存超载的可能性

2:内存的使用量等于swap的大小+RAM*overcommit_ratio的值。假设希望减小内存的过度使用,这个值是最安全的

overcommit_ratio:

将overcommit_memory指定为2时候,提供的物理RAM比例,默觉得50

六.与通信相关的调优參数

常见在同一个主机中进行进程间通信的方式:

1.通过消息message;2.通过signal信号量进行通信;3.通过共享内存进行通信,跨主机常见的通信方式是rpc

以消息的方式实现进程通信的调优方案:

msgmax:以字节为单位规定消息队列中随意消息的最大同意大小。这个值一定不能超过该队列的大小(msgmnb)。默认值为65536

msgmnb:以字节为单位规定单一消息队列的最大值(最大长度)。默觉得65536字节

msgmni:规定消息队列识别符的最大数量(及队列的最大数量)。64位架构机器的默认值为1985;32位架构机器的默认值为1736

以共享内存方式实现进程通信的调优方案:

shmall:以字节为单位规定一次在该系统中能够使用的共享内存总量(单次申请的上限)

shmmax:以字节为单位规定每个共享内存片段的最大大小

shmmni:规定系统范围内最大共享内存片段。在64和32位的系统上默认值都是4096

七.与容量相关的文件系统可调优參数:

file-max:列出内核分配的文件句柄的最大值

dirty_ratio:规定百分比值,当脏数据达到系统内存总数的这个百分比值后開始运行pdflush,默觉得20

dirty_background_ratio:规定百分比值。当某一个进程自己所占用的脏页比例达到系统内存总数的这个百分比值后開始在后台运行pdflush。默觉得10

dirty_expire_centisecs:pdlush每隔百分之中的一个秒的时间开启起来刷新脏页,默认值为3000。所以每隔30秒起来開始刷新脏页

dirty_writeback_centisecs:每隔百分之中的一个秒開始刷新单个脏页。

默认值为500,所以一个脏页的存在时间达到了5秒。就開始刷新脏

八.linux内存经常使用的观察指标命令:

Memory activity

vmstat [interval] [count]

sar -r [interval] [count]

Rate of change in memory

sar -R [interval] [count]

frmpg/s:每秒释放或者分配的内存页,假设为正数,则为释放的内存页。假设为负数,则为分配的内存页

bufpg/s:每秒buffer中获得或者释放的内存页。假设为正数则为获得的内存页,为负数。则为释放的内存页

campg/s:每秒cache中获得或者释放的内存页。

假设为正数则为获得的内存页。为负数。

则为释放的内存页

Swap activity

sar -W [interval] [count]

ALL IO

sar -B [interval] [count]

pgpgin/s:每秒从磁盘写入到内核的块数量

pgpgout/s:每秒从内核写入到磁盘的块数量

fault/s:每秒钟出现的缺页异常的个数

majflt/s:每秒钟出现的大页异常的个数

pgfree/s:每秒回收回来的页面个数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: