Linux的存储管理
Buddy内存管理算法
- Buddy算法是经典的内存管理算法,也是实际在Linux中运行的一种内存管理算法
- 算法基于计算机处理二进制的优势具有极高的效率
- 算法主要是为了解决内存外碎片的问题
页内碎片
: 内部碎片是已经被分配出去(能明确指出属于哪个进程)的内存空间大于请求所需的内存空间,不能被利用的内存空间就是内部碎片。页外碎片
: 外部碎片是指还没有分配出去(不属于任何进程),但是由于太小而无法分配给申请内存空间的新进程的内存空闲块
- Buddy算法的目的就是努力让内存分配与相邻内存合并能快速进行
- Buddy内存分配原则
- 向上取整为2的幂大小1,例如
- 70k -> 128k
- 129k -> 256k
- 666k -> 1024k
- 向上取整为2的幂大小1,例如
- Buddy伙伴系统介绍
- "伙伴" 指的是内存的 "伙伴"
- 一片连续内存的 "伙伴" 是相邻的另一片大小一样的连续内存
-
Buddy伙伴系统逻辑图解
- 创建一系列空闲块链表,每一种都是2的幂
- 根据下图,假设存储空间有1M大小,假设要分配100k内存
- 100k向上取2的幂=128k
- 查询是否有128k空闲内存块?
- 没有!查询是否有256k空闲内存块?
- 没有!查询是否有512k空闲内存块?
- 没有!查询是否有1M空闲内存块?
- 有,摘下1M空闲内存块,分配出去
- 拆下512k放在512k的空闲链表,其余的分配出去
- 拆下256k放在256k的空闲链表,其余的分配出去
- 拆下128k放在128k的空闲链表,其余的分配出去
- 分配完毕
- 回收刚才分配的内存
- 判断刚才分配的内存伙伴在空闲链表上吗?
- 在!移除伙伴,合并为256k空闲内存,判断
- 在!移除伙伴,合并为512k空闲内存,判断
- 在!移除伙伴,合并为1M空闲内存
- 插入1M空闲链表,回收完成
-
Buddy内存管理算法是将内存外碎片的问题转换成了内存内碎片问题,但是也大大提升了整体性能,因为内存外碎片要比内存内碎片要大。
Linux交换空间
- 交换空间(Swap)是磁盘的一个分区
- Linux物理内存满时,会把一些内存交换至Swap空间
- Swap空间是初始化系统时配置的
在Linux里查看swap
- 查看系统Swap空间
[root@jartins elastic_notes]# top top - 16:29:24 up 4 days, 15:26, 1 user, load average: 0.09, 0.06, 0.05 Tasks: 102 total, 1 running, 99 sleeping, 2 stopped, 0 zombie %Cpu(s): 0.5 us, 0.2 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 3688724 total, 1409184 free, 555956 used, 1723584 buff/cache KiB Swap: 1049596 total, 1049596 free, 0 used. 2826512 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- swap存储在磁盘,效率较低,不建议过多使用
Swap交换空间有什么用呢
- 冷启动内存依赖:对于一些大型的应用程序,在启动的过程中会使用大量的内存,但是这些内存只是在启动的时候用一下,后续在运行中很少再使用到这个内存,因此有个这个交换空间,系统就可以将不常用的信息交换存放到磁盘里面去,从而释放更多的物理内存,提供给系统使用。
- 系统睡眠依赖:当Linux系统需要睡眠的时候,它就需要把系统里所有内存数据都保存到swap空间里面去的,等下次启动的时候就会重新从swap获取数据,这样就提升了系统的启动速度
- 大进程空间依赖:有些进程需要很多的内存空间,但是物理内存是不够使用的,因此需要把进程使用到的这些内存暂时保存到swap磁盘空间中去,使得大的进程也能够运行起来
Swap空间与虚拟内存的差异
Swap空间 | 虚拟内存 |
---|---|
Swap存在于磁盘 | 虚拟内存存在于磁盘 |
Swap空间与主从发生置换 | 虚拟内存与主存发生置换 |
Swap空间是操作系统概念 | 虚拟内存是进程概念 |
Swap空间解决系统物理内存不足问题 | 虚拟内存解决进程物理内存不足问题 |
-
向上取整到2的幂,指的是将一个数向上取整到最近的2的幂次方。
例如,将7向上取整到2的幂次方,结果为8,因为2的3次方等于8,而2的2次方等于4,所以向上取整到最近的2的幂次方是将7四舍五入到8。
对于任何一个正整数n,都可以将它转换为一个二进制数。将二进制数从右往左数,遇到0就跳过,遇到1时就将前一个数变成1并停止继续向右数,这时候剩余的数就是转换后二进制数长度。例如,n=7的二进制为111,从右往左数,遇到0跳过,遇到1时就将前一个数变成1并停止继续向右数,所以7的二进制数为1000000,长度为7。
根据上述方法,我们可以将任何正整数n转换为一个长度为k的二进制数,其中k为n的二进制长度。然后将这个二进制数从右往左数,遇到第一个1时停止,将前一个数变为1并输出,输出的数就是向上取整到最近的2的幂次方。
例如,n=10的二进制为1010,长度为4。从右往左数,第一个1在第三位,所以将第四位变为1并输出,输出的数为1000,即2的4次方。
以下是Python代码实现:
↩def ceil_pow2(n): k = 0 while n: n = n >> 1 k += 1 return 1 << (k - 1) print(ceil_pow2(7)) # 输出8 print(ceil_pow2(10)) # 输出16