上一节咱们谈了Linux的进程管理:缓存
这一节咱们将谈下Linux的内存体系架构
进程执行过程当中,Linux内核根据须要给进程分配一块内存区域。进程就把这片区域做为工做区,按要求执行操做。这就像给你分配一张本身的桌子,你能够在桌子上摆放文档,备忘录,开展本身的工做。区别在于,内核以更加动态的方式分配空间。系统上运行的进程常常是成千上万的,可是内存倒是有限的。因而,Linux必须高效的处理内存问题。在本节中,将介绍Linux内存架构、地址布局、以及Linux如何高效管理内存空间。app
先简单总结下,若是内存有限的状况下,好比8G,你开启了大量的应用,势必会致使电脑卡顿,运行缓慢,甚至无反应的!函数
现实中,咱们常常会面临32位仍是64位操做系统的选择(虽然如今32位已经基本淘汰了),对用户来讲,它们间最大的差异是可否支持4GB以上的虚拟内存空间。站在性能的角度来理解32位和64位的系统,Linux映射物理内存到虚拟内存的区别是十分有趣的。以下图所示,能够明显看出内存映射方式在32位和64位系统上的区别。咱们不去详尽探索物理内存映射到虚拟内存的细节,对于性能调优,咱们只须要了解一下Linux的内存架构的一些知识就够了。布局
32位架构的机器上,Linux内核只能直接映射第一个GB的的物理内存(896M,由于还要考虑到保留的空间)。在此上的内存被称做ZONE_NORMAL,这部分空间必须映射到最下面的1GB。这种映射对应用程序是彻底透明的,可是分配内存页到ZONE_HIGHMEM会形成一点 点性能损耗。post
另外一方面,在64位系统上,例如在IA-64上面,ZONE_NORMAL一直延伸到64GB或者128GB。如你所见,把内存页从ZONE_HIGHMEM映射到ZONE_NORMAL这种损耗在64位系统上是不存在的。性能
下图展现了32位和64位架构Linux系统的虚拟寻址布局:spa
在32位架构上,单个进程能够利用的最大地址空间是4GB,这是受到了32位虚拟内存映射的限制。在标准的32位环境中,虚拟地址被划分为3GB的用户空间和1GB的内存空间,现实中也存在一些4GB/4GB地址布局。操作系统
再说64位架构,由于没有内存限制存在,每一个进程可以都有可能使用巨大的地址空间。
因为操做系统把全部内存都映射成虚拟内存,因此,操做系统的物理内存架构对用户和应用程序一般都是不可见的。若是咱们要掌握Linux内存调优的办法,就必须先理解Linux如何处理虚拟内存。如3.1所说的那样,应用程序不使用物理内存,而是向Linux内核请求一个特定大小的内存映射,而且收到一个虚拟内存的映射。以下图所示,虚拟内存没必要要必定是物理内存的映射,若是某个应用程序使用了一块超大的虚拟内存,这虚拟内存其中某一部分多是由磁盘上的swap空间映射来的。
从图中能够看出来,应用程序常常不是直接写入磁盘子系统,而是首先写入cache或者buffer,而后,在pdflush空闲的时候、或者某个文件大小超出buffer和cache的时候,由pdflush内核线程把buffer或cache中的数据写入磁盘。参考后面的写入脏buffer部分。
Linux内核管理磁盘缓存的方式,和内核写数据到文件系统的方式有紧密联系。和其它操做系统都只分配特定的部份内存做为磁盘缓存的方式相比,Linux处理内存资源更加高效。
虚拟内存管理器默认配置把全部的可用空闲内存空间做为磁盘缓存,因此,常常能够见到Linux系统明明拥有数GB级的内存,却只有20M处于空闲状态。
Linux一样高效利用swap空间,当操做系统开始使用swap空间的时候,并不表示系统出现了内存瓶颈,而是证实了Linux如何有效的使用系统资源。参考页帧回收(page frame reclaiming)。
下面简单介绍下几个重要概念:
- 页帧分配(Page frame allocation)
页是物理内存或虚拟内存中一组连续的线性地址,Linux内核以页为单位处理内存,页的大小一般是4KB。当一个进程请求必定量的页面时,若是有可用的页面,内核会直接把这些页面分配给这个进程,不然,内核会从其它进程或者页缓存中拿来一部分给这个进程用。内核知道有多少页可用,也知道它们的位置。
- 伙伴系统(Buddy system)
Linux内核使用名为伙伴系统(Buddy system)的机制维护空闲页。伙伴系统维护空闲页面,而且尝试给发来页面申请的进程分配页面,它还努力保持内存区域是连续的。若是不考虑到零散的小页面可能会致使内存碎片,并且在要分配一个连续的大内存页时将变得很困难,这就可能致使内存使用效率下降和性能降低。下图说明了伙伴系统如何分配内存页:
若是尝试分配内存页失败,就启动回收机制。能够在/proc/buddyinfo文件看到伙伴系统的信息:
- 页帧回收
若是在进程请求指定数量的内存页时没有可用的内存页,内核就会尝试释放特定的内存页(之前使用过,如今没有使用,而且基于某些原则仍然被标记为活动状态)给新的请求使用。这个过程叫作内存回收。kswapd内核线程和try_to_free_page()内核函数负责页面回收。
kswapd一般在task interruptible状态下休眠,当一个区域中的空闲页低于阈值的时候,它就会被伙伴系统唤醒。它基于最近最少使用原则(LRU,Least Recently Used)在活动页中寻找可回收的页面。最近最少使用的页面被首先释放。它使用活动列表和非活动列表来维护候选页面。kswapd扫描活动列表,检查页面的近期使用状况,近期没有使用的页面被放入非活动列表中。使用vmstat -a命令能够查看有分别有多少内存被认为是活动和非活动状态:
kswapd还要遵循另一个原则。页面主要有两种用途:页面缓存(page cahe)和进程地址空间(process address space)。页面缓存是指映射到磁盘文件的页面;进程地址空间的页面(又叫作匿名内存,由于不是任何文件的映射,也没有名字)使用来作堆栈使用的。在回收内存时,kswapd更偏向于回收页面缓存。
若是大部分的页面缓存和进程地址空间来自于内存回收,在某些状况下,可能会影响性能。咱们能够经过修改/proc/sys/vm/swappiness文件来控制这个行为:
- swap分区
在发生页面回收时,属于进程地址空间的处于非活动列表的候选页面会发生page out。拥有交换空间自己是很正常的事情。在其它操做系统中,swap无非是保证操做系统能够分配超出物理内存大小的空间,可是Linux使用swap的空间的办法更加高效。虚拟内存由物理内存和磁盘子系统或者swap分区组成。在Linux中,若是虚拟内存管理器意识到内存页已经分配了,可是已经好久没有使用,它就把内存页移动到swap空间。
Page out和swap out:“page out”和“swap out”很容易混淆。“page out”意思是把一些页面
(整个地址空间的一部分)交换到swap;"swap out"意味着把全部的地址空间交换到swap。
复制代码
虚拟内存由物理内存和磁盘子系统或者swap分区组成。这话的意思是,物理内存,磁盘还有swap分区这些物理设备合在一块儿被抽象虚拟成了一个大内存,叫作虚拟内存。进程在虚拟内存上分配的地址会被映射道物理设备上,因此可能部分在物理内存,可能在swap分区,多是磁盘上(我的理解)。
基于上述,有一下几点理解:
每一个进程都有本身独立的4G内存空间而这4G内存空间只是虚拟内存空间,每次访问内存空间的某个地址,都须要把地址翻译为实际物理内存地址
一个新进程创建的时候,将会创建起本身的内存空间,此进程的数据,代码等从磁盘拷贝到本身的进程空间,哪些数据在哪里,都由进程控制表中的task_struct记录,task_struct中记录中一条链表,记录中内存空间的分配状况,哪些地址有数据,哪些地址无数据,哪些可读,哪些可写,均可以经过这个链表记录
全部进程共享同一物理内存,每一个进程只把本身目前须要的虚拟内存空间映射并存储到物理内存上(参考3.1)。
进程要知道哪些虚拟内存地址上的数据在物理内存上,哪些不在,还有在物理内存上的位置,须要用页表来记录
页表的每个表项分两部分,第一部分记录此页是否在物理内存上,第二部分记录物理内存页的地址(若是在的话)
当进程访问某个虚拟地址,去看页表,若是发现对应的数据不在物理内存中,则缺页异常。缺页异常的处理过程,就是把进程须要的数据从磁盘上拷贝到物理内存中,若是内存已经满了,没有空地方了,那就找一个页覆盖,固然若是被覆盖的页曾经被修改过,须要将此页写回磁盘
谈完Linux的内存体系,下一节将会谈一下Linux的文件系统