今天我们来谈谈 Linux 的内存机制。
首先我们理一下概念
一、什么是 linux 的内存机制?
我们知道,直接从实体内存读写资料要比从硬碟读写资料要快的多,因此,我们希望所有资料的读取和写入都在内存完成,而内存是有限的,这样就引出了实体内存与虚拟内存的概念。
实体内存就是系统硬体提供的内存大小,是真正的内存,相对于实体内存,在 linux 下还有一个虚拟内存的概念,虚拟内存就是为了满足实体内存的不足而提出的策略,它是利用磁碟空间虚拟出的一块逻辑内存,用作虚拟内存的磁碟空间被称为交换空间(Swap Space)。
作为实体内存的扩充套件,linux 会在实体内存不足时,使用交换分割槽的虚拟内存,更详细的说,就是核心会将暂时不用的内存块资讯写到交换空间,这样以来,实体内存得到了释放,这块内存就可以用于其它目的,当需要用到原始的内容时,这些资讯会被重新从交换空间读入实体内存。
Linux 的内存管理采取的是分页存取机制,为了保证实体内存能得到充分的利用,核心会在适当的时候将实体内存中不经常使用的资料块自动交换到虚拟内存中,而将经常使用的资讯保留到实体内存。
要深入了解 linux 内存执行机制,需要知道下面提到的几个方面:
Linux 系统会不时的进行页面交换操作,以保持尽可能多的空闲实体内存,即使并没有什么事情需要内存,Linux 也会交换出暂时不用的内存页面。这可以避免等待交换所需的时间。
Linux 进行页面交换是有条件的,不是所有页面在不用时都交换到虚拟内存,linux 核心根据” 最近最经常使用 “演算法,仅仅将一些不经常使用的页面档案交换到虚拟 内存,有时我们会看到这么一个现象:linux 实体内存还有很多,但是交换空间也使用了很多。其实,这并不奇怪,例如,一个占用很大内存的程序执行时,需 要耗费很多内存资源,此时就会有一些不常用页面档案被交换到虚拟内存中,但后来这个占用很多内存资源的程序结束并释放了很多内存时,刚才被交换出去的页面 档案并不会自动的交换进实体内存,除非有这个必要,那么此刻系统实体内存就会空闲很多,同时交换空间也在被使用,就出现了刚才所说的现象了。关于这点,不 用担心什么,只要知道是怎么一回事就可以了。
交换空间的页面在使用时会首先被交换到实体内存,如果此时没有足够的实体内存来容纳这些页 面,它们又会被马上交换出去,如此以来,虚拟内存中可能没有足够空间来储存这些交换页面,最终会导致 linux 出现假宕机、服务异常等问题,linux 虽 然可以在一段时间内自行恢复,但是恢复后的系统已经基本不可用了。
因此,合理规划和设计 Linux 内存的使用,是非常重要的.
在 Linux 操作系统中,当应用程式需要读取档案中的资料时,操作系统先分配一些内存,将资料从磁碟读入到这些内存中,然后再将资料分发给应用程式;当需要往档案中写 资料时,操作系统先分配内存接收使用者资料,然后再将资料从内存写到磁碟上。然而,如果有大量资料需要从磁碟读取到内存或者由内存写入磁碟时,系统的读写性 能就变得非常低下,因为无论是从磁碟读资料,还是写资料到磁碟,都是一个很消耗时间和资源的过程,在这种情况下,Linux 引入了 buffers 和 cached 机制。
buffers 与 cached 都是内存操作,用来储存系统曾经开启过的档案以及档案属性资讯,这样当操作系统需要读取某些档案时,会首先在 buffers 与 cached 内存区查询,如果找到,直接读出传送给应用程式,如果没有找到需要资料,才从磁碟读取,这就是操作系统的 WordPress 加速缓存机制,通过 WordPress 加速缓存,大大提高了操 作系统的效能。但 buffers 与 cached 缓冲的内容却是不同的。
buffers 是用来缓冲块装置做的,它只记录档案系统的后设资料(metadata)以及 tracking in-flight pages,而 cached 是用来给档案做缓冲。更通俗一点说:buffers 主要用来存放目录里面有什么内容,档案的属性以及许可权等等。而 cached 直接用来记忆我们开启过的档案和程式。
为了验证我们的结论是否正确,可以通过 vi 开启一个非常大的档案,看看 cached 的变化,然后再次 vi 这个档案,感觉一下两次开启的速度有何异同,是不是第二次开启的速度明显快于第一次呢? 接著执行下面的命令:
find /* -name *.conf
看看 buffers 的值是否变化,然后重复执行 find 命令,看看两次显示速度有何不同。
二、 linux 什么时候开始使用虚拟内存(swap)?
A.[root@wenwen ~]# cat /proc/sys/vm/swappiness
60
上面这个 60 代表实体内存在使用 60% 的时候才会使用 swap
swappiness=0 的时候表示最大限度使用实体内存,然后才是 swap 空间,
swappiness=100 的时候表示积极的使用 swap 分割槽,并且把内存上的资料及时的搬运到 swap 空间里面。
通常情况下:
swap 分割槽设定建议是内存的两倍(内存小于等于 4G 时),如果内存大于 4G,swap 只要比内存大就行。另外尽量的将 swappiness 调低,这样系统的效能会更好。
B. 修改 swappiness 引数
临时性修改:
[root@wenwen ~]# sysctl vm.swappiness=10
vm.swappiness = 10
[root@wenwen ~]# cat /proc/sys/vm/swappiness
10
永久性修改:
[root@wenwen ~]# vim /etc/sysctl.conf
加入引数:
vm.swappiness = 35
然后在直接:
[root@wenwen ~]# sysctl -p
检视是否生效:
cat /proc/sys/vm/swappiness
35
三、怎么释放内存?
一般系统是不会自动释放内存的
关键的配置档案/proc/sys/vm/drop_caches 。这个档案中记录了 WordPress 加速缓存释放的引数,预设值为 0,也就是不释放 WordPress 加速缓存。他的值可以为 0~3 之间的任意数字,代表著不同的含义:
0 – 不释放 1 – 释放页 WordPress 加速缓存 2 – 释放 dentries 和 inodes 3 – 释放所有 WordPress 加速缓存
实操:
很明显多出来很多空闲的内存了吧
四、怎么释放 swap?
前提:首先要保证内存剩余要大于等于 swap 使用量,否则会宕机!根据内存机制,swap 分割槽一旦释放,所有存放在 swap 分割槽的档案都会转存到实体内存上。通常通过重新挂载 swap 分割槽完成释放 swap 。
a. 检视当前 swap 分割槽挂载在哪?
b. 关停这个分割槽
c. 检视状态:
d. 检视 swap 分割槽是否关停,最下面一行显示全 0
e. 将 swap 挂载到/dev/sda5 上
f. 检视挂载是否成功
五、一些实际的小例子?
我在设定 mysql 的时候,将
my.cnf 档案
innodb_buffer_pool_size = 6G(我操作系统的内存就是 6G,一般这个值设定为操作系统内存的 80%)
这个值并不是设定的越大越好。设定的过大,会导致 system 的 swap 空间被占用,导致操作系统变慢,从而减低 sql 查询的效率。
这里你可以这么理解,当我将这个 buffer_pool_size 设定得过大,跟操作系统内存一样大的时候,我使用 mysql, 会在一段时间内呼叫大量的资料进内存,由于 linux 的内存机制,再根据最近最优的原则,将一部分资料筛选放入 swap 分割槽,而 swap 分割槽没有及时的清理掉资料,当再次呼叫其它资料的时候,又会将一部分资料筛选放入 swap 分割槽,可能会出现一个现象,就是实体内存还有剩余,甚至是空的,而 swap 分割槽却是满的。