内存管理

Swap

swap可以避免应用程序因内存不足而崩溃,但它的性能远不及内存,适用于特殊场景(例如我的ecs只有2G内存😅)。实现方式可以基于交换文件,也可以基于磁盘分区,并且内核参数vm.swappiness可以定义swap与内存的使用占比,即优先使用内存还是swap。


创建一个交换文件作为Swap

# 创建一个交换文件作为Swap
dd if=/dev/zero of=/swapfile bs=1M count=4096

# 设置合适的权限
chmod 600 /swapfile

# 将文件格式化为swap空间
mkswap /swapfile

# 启用swap文件
swapon /swapfile

# 持久化
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# 检查Swap是否已启用
free -h
swapon --show

使用磁盘分区作为Swap

如果你想将整个磁盘分区作为swap,而不是使用交换文件,可以按照以下步骤进行:

  1. 创建swap分区(可以使用fdiskparted工具):
  • 使用fdisk创建一个新的Linux swap分区,通常选择类型为82(Linux swap)。
  1. 格式化该分区为swap格式
sudo mkswap /dev/sdXn  # 替换 /dev/sdXn 为你刚刚创建的分区
  1. 启用swap分区
sudo swapon /dev/sdXn
  1. 确保分区在启动时自动启用: 修改/etc/fstab文件,添加如下内容:
/dev/sdXn none swap sw 0 0

Swap相关内核参数

vm.swappiness是Linux内核中用来控制交换的行为的参数。它的值决定了内存满时交换的优先级。值的范围是01000表示内存几乎用完之前不会交换,100表示内存稍微紧张时就会使用swap。

查看当前swappiness值:

cat /proc/sys/vm/swappiness

临时调整swappiness

sudo sysctl vm.swappiness=30  # 设置为30,降低交换的频率

永久更改swappiness: 编辑/etc/sysctl.conf文件,加入:

vm.swappiness=30

然后执行:

sudo sysctl -p

buffer

  • Buffers 是内核缓冲区用到的内存

    • 对应的是 /proc/meminfo 中的 Buffers 值。

    • # cat /proc/meminfo 
      ...
      Buffers:            2104 kB 
      ...
  • Buffers 是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据,通常不会特别大(20MB 左右)。这样,内核就可以把分散的写集中起来,统一优化磁盘的写入,比如可以把多次小的写合并成单次大的写等等。合并这里似乎和大数据生态中的Hadoop组件中的小文件合并有相似。

  • 缓冲区,数据写入磁盘前暂时存放的空间

cache

  • Cache 是内核页缓存和 Slab 用到的内存

    • 对应的是 /proc/meminfo 中的 Cached 与 SReclaimable 之和。

    • # cat /proc/meminfo |grep SReclaimable
      ...
      Cached:          1079152 kB
      ...
      SReclaimable:     125492 kB
      ...
  • Cached 是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据。这样,下次访问这些文件数据时,就可以直接从内存中快速获取,而不需要再次访问缓慢的磁盘。

  • 缓存区,将磁盘中的内容暂时读入到cache中可以提高效率

范例:

[root@8 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:          941Mi       174Mi       580Mi       6.0Mi       186Mi       620Mi
Swap:            0B          0B          0B
[root@8 ~]# dd if=/dev/sda of=/dev/null bs=300M

#buff/cache明显增加
[root@8 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:          941Mi       169Mi       365Mi       6.0Mi       405Mi       623Mi
Swap:            0B          0B          0B

清除buff/cache

  • 生产中不要使用,因为buff/cache是可以提高效率的,并且改成3后将改不回默认值0了 除非重启
  • 帮助:man proc
[root@centos8 ~]#echo 3 > /proc/sys/vm/drop_caches
[root@centos8 ~]#free -h
             total       used       free     shared buff/cache   available
Mem:          1.8Gi       320Mi       1.3Gi       9.0Mi       152Mi       1.3Gi
Swap:         2.0Gi         0B       2.0Gi

buff & cache 总结

  • 为了提高文件的写入效率,在现代的操作系统中,当用户调用 write 函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满、或者超过了指定的时限之后,才真正的将缓冲区中的数据写入到磁盘里。

  • 这种做法虽然提高了效率,但是也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里的写入数据将会丢失。

  • 为此,系统提供了 fsync 和 fdatafync 两个同步函数,它们可以强制让操作系统立即将缓冲区的数据写入到磁盘里面,从而确保写入数据的安全性。

  • 好比你在 window 系统打开一个 word 文档,当你写一些内容时就相当于写入,但是你写的内容并没有真正的保存,而是放在一个缓冲区,如果这时关闭的话内容就会丢失。只有当你点击保存时内容才真正的保存(同步)到磁盘,点击保存就好比调用同步函数 fsync 和 fdatafync。

buff & cache 相关工具

free # 查看内存使用量 以及内存中buff/cache的使用量

sync # 将缓冲区的数据写入到持久存储中

内存寻址范围

寻址范围计算公式:内存容量(MB)*8 / 字长(按字编址)

  • 若某台小米笔记本Air 13.3中字长为64位,内存容量为12GB,按字编址,则这台小米笔记本可寻址范
    围为(1536M )
    
    
    1GB =1024MB
    故寻址范围 = 12*1024*8 / 64 = 12*128 =1536M

SWAP

  • **buffer:**缓冲区(数据写入磁盘前 临时存放的空间)
  • **cache:**缓存(将磁盘的数据导入到内存中 提高数据的访问速度)

swap 概述

  • 临时利用磁盘顶替内存空间(避免因内存不足而导致程序执行失败),但性能较差,因为磁盘的性能远不及内存
  • 生产中通常禁用swap

swap 相关内核参数

  • /proc/sys/vm/swappiness 的值决定了当内存占用达到一定百分比时,会启用swap分区空间

  • 范例:

[root@aliyun ~]# cat /proc/sys/vm/swappiness 
30

#临时修改此值
[root@aliyun ~]# echo 0 > /proc/sys/vm/swappiness
  • **说明:**内存在使用到100-30=70%的时候,就开始使用swap空间。简单说这个值就是定义了swap的使用倾向,默认值为30,值越大表示越倾向于使用swap。可以设为0,0表示最大限度的减少使用swap,而不是不使用swap。

swap 相关命令

查看swap:

  • swapon -s(本质上就查看:cat /proc/swaps)

    • # 如果配置有多个swap分区或者文件的话,这里将会有多行,每行代表一个正在被系统使用的swap分区或文件
      dev@dev:~$ swapon -s
      Filename                Type        Size    Used    Priority
      /dev/dm-1               partition   524284  0       -1
      
      
      Filename # 如果swap类型是分区,这里将是分区的路径,如果swap类型是文件,这里将是文件的路径
      
      Type # swap的类型,partition代表这是一个swap分区,file代表这是一个swap文件
      
      Size # swap的大小,单位是k,这里524284表示的差不多是512M
      
      Used # 已经被使用的大小,这里0表示还没有被使用到
      
      Priority # 优先级,优先级高的swap将会被优先使用,同等优先级的swap将会被均匀的使用(round-robin算法),优先级可以通过“swapon -p”命令来设置
  • free -h

  • top

临时禁用swap:

  • swapoff /dev/sdc1

创建swap文件系统:

  • mkswap

同步swap:

  • swapon -a(创建swap后不会立即生效,需要创建swap文件系统后进行同步)

swap 的效率对比

  • 整块硬盘的swap > 基于分区的swap > 基于文件的swap
  • 基于分区的swap 靠前的分区要比靠后的分区速度快,但仅限于普通磁盘,因为分区考前就表示磁道也靠外,普通磁盘读取数据是从磁道外到内读取的

swap 创建

基于分区创建 swap

  • 注意:磁盘分区操作一定要小心,弄不好就会造成数据丢失、系统挂掉的后果。
# 创建swap分区
# fdisk /dev/
...
Last sector, +sectors or +size{K,M,G,T,P} (169873408-209715199, default 209715199): +2G #添加一个2G的分区
Command (m for help): t # 修改文件系统类型
Partition number (1-5, default 5): 5
...
Hex code (type L to list all codes): 82 # 82表示swap分区
...
Command (m for help): p
...
/dev/sda5       169873408 174067711   4194304   2G 82 Linux swap / Solaris
Command (m for help): w # 存盘退出


# 创建文件系统
# mkswap /dev/sda5


# 查看创建文件系统后的swap
# lsblk -f /dev/sda5
NAME FSTYPE LABEL UUID                                 MOUNTPOINT
sda5 swap         548ed2f6-e829-4489-b2ae-471c623c858b
# blkid /dev/sda5
/dev/sda5: UUID="548ed2f6-e829-4489-b2ae-471c623c858b" TYPE="swap" PARTUUID="c0a5b2de-05"


# 挂载
# vim /etc/fstab
...
UUID=548ed2f6-e829-4489-b2ae-471c623c858b swap                    swap    defaults        0 0


# 同步swap
# swapon -a

# 查看创建的swap
# free -h
              total        used        free      shared  buff/cache   available
Mem:          941Mi       190Mi       587Mi       6.0Mi       163Mi       604Mi
Swap:         2.0Gi          0B       2.0Gi
# swapon -s
Filename                                Type            Size    Used    Priority
/dev/sda5                               partition       2097148 0       -2
# cat /proc/swaps
Filename                                Type            Size    Used    Priority
/dev/sda5                               partition       2097148 0       -2

基于文件 swap

  • 注意:不是所有的文件系统都支持创建swap文件,如btrfs,在btrfs分区里创建swap文件将失败。
# 创建swap文件
# dd if=/dev/zero of=/data/swapfile bs=1M count=1024

# 将文件权限改为600,否则创建时会报错
# chmod 600 /data/swapfile

# 创建文件系统
# mkswap /data/swapfile

# 挂载
# vim /etc/fstab
...
/data/swapfile                            swap                    swap    defaults        0 0

# 同步swap
# swapon -a

# 查看创建的swap
# free -h
              total        used        free      shared  buff/cache   available
Mem:          941Mi       195Mi        60Mi       3.0Mi       685Mi       602Mi
Swap:         3.0Gi       4.0Mi       3.0Gi
# swapon -s
Filename                                Type            Size    Used    Priority
/dev/sda5                               partition       2097148 4364    -2
/data/swapfile                          file            1048572 0       -3

基于磁盘创建 swap

  • 通常不这么做,因为使用整块硬盘空间来创建swap太大了

swap 优先级

  • 优先级数值越高 则越优先使用此swap设备
# 提升swap的优先级
pri=number # 使用fstab文件挂载时在defaults处修改
# 然后可以使用swapon -s查看

swap 禁用

# 停掉所有系统正在使用的swap
# swapoff -a
 
#swapon -s命令没有任何输出,free命令显示swap空间为0,说明swapoff成功
# swapon -s
# free
              total        used        free      shared  buff/cache   available
Mem:         500192       35924      348888        2004      115380      433924
Swap:             0           0           0
 
# 当然我们还需要修改/etc/fstab,否则下次重启后,系统又会重新挂载相应的swap分区和文件
# 使用自己喜欢的编辑器,将/etc/fstab中跟swap相关的三行删掉即可(本例中是三行,请根据实际情况调整)

swap 范例

#未启用swap
# free -h
              total        used        free      shared  buff/cache   available
Mem:          941Mi       204Mi       365Mi        18Mi       371Mi       562Mi
Swap:            0B          0B          0B


#600M的文件可以创建
# dd if=/dev/zero of=file.img bs=600M count=1
# ll -h file.img
-rw-r--r-- 1 root root 600M Apr  5 10:45 file.img


#800M的文件就已经提示进程被kill掉了,其实就是内存不足所导致
# dd if=/dev/zero of=file2.img bs=800M count=1
Killed
# ll -h file2.img
-rw-r--r-- 1 root root 0 Apr  5 10:47 file2.img


#添加swap


#再次测试

查看系统中swap in/out的情况

并不是swap空间占用多就一定性能下降,真正影响性能是swap in和out的频率,频率越高,对系统的性能影响越大,我们可以通过vmstat命令来查看swap in/out的频率

如果swap容量固定不变,那内存就不是瓶颈。可以用vmstat 1命令看,si so两列的数值在不断变化时,内存就不够了。

# 参数2表示每两秒统计一次,si和so两列就是每秒swap in和out的次数
dev@ubuntu:~$ vmstat 2
procs------------memory--------------swap----io-----system-----------cpu-----
 r b    swpd  free  buff cache      si so   bi bo   in  cs      us sy id wa st
 0 0    70232 75620 7940 209476     0  0    0  0    111 180     0  1  99 0  0
 0 0    70232 75620 7940 209476     0  0    0  0    116 186     1  1  99 0  0
 0 0    70228 75620 7940 209476     2  0    2  0    120 193     1  1  98 1  0
 0 0    70228 75620 7940 209476     0  0    0  0    117 186     0  0  100 0 0
 0 0    70228 75620 7940 209476     0  0    0  0    113 184     0  1  99 0  0