本网站相关文章:

Cache and Buffer

Cache

A cache is something that has been “read” from the disk, and stored for later use. 其数据流通方向:disk---<read>---mem(驻留)<--->cpu, 此时对于 cpu 来说内存中的缓存就是 Cache.
cache 是 cpu 与内存之间, 用于解决速度不对等问题, 将最频繁,最近使用的数据放在 cache 中, 避免再次从 disk 中读取, 减少了 CPU 的等待, 其中涉及高速缓存, 寄存器相关知识见IO 相关术语说明.

Buffer

A buffer is something that has yet to be “written” to disk. 数据流通角色: cpu---mem(驻留)---<write>---disk, 此时对于程序或者 CPU 来说内存的缓存是 Buffer 以便在指定的时间将所有 buffer 全部刷新到磁盘上.
buffer 是内存和磁盘之间, 根据磁盘的读写设计, 将分散的写集中进行, 减少磁盘碎片和反复寻道. buffer 涉及磁盘 IO, I/O 缓存等知识. 我们可以通过命令sync手动清空缓存, 关于缓存存在的例证可以见如下示例: 将文件拷贝到 U 盘, 当文件拷贝结束时, 系统仍旧提示 U 盘在使用中, 此时文件缺失拷贝到 buffer 中, 但是还没有彻底拷贝到 U 盘上.

注意, 这里关于 cache 和 buffer 仅仅在很小的场景下才可以分割开来(数据流向), 大部分情况下, 在内存和磁盘之间两者是一致的.

Page cache

页缓存是针对文件系统, 文件的缓存, 在文件层面上的数据会在 page cache 中, 其将部分空闲的物理内存用来缓存部分磁盘中访问频繁的文件内存(局部性原理), 此时这部分用于缓存磁盘文件的内存就叫做 page cache.

  • 文件系统的 cache.
  • free 命令中的 cache.

PS: 缓存存在的理论基础就是局部性原理.

Buffer cache

针对磁盘块, 在不存在文件系统情况下下, 直接对磁盘的操作会被缓存到 buffer cache 中, 最终在某个时间段将这些 buffer 信息刷新到指定的物理磁盘上.

  • 块设备的读写缓冲区.
  • free 命令中的 buffer.

Virtual Memory

虚拟内存

Virtual Memory, 一种内存管理技术, 通过页映射机制(见程序员的自我修养一书), 获取一个”逻辑上”的虚拟内存连续地址空间, 重复利用”实际上”的物理内存碎片, 其实际上是一个内存交换区.
虚拟内存能够让程序突破物理内存限制, 理论上能够使用的内存范围根据总线位数决定, 同时基于进程安全保护网确保每一个进程的内存不受其他程序干扰.

虚拟内存地址

  • Virtual Address Space: 每一个程序运行时都拥有自己的虚拟地址空间, 其根据计算机位数和地址总线来寻址, 从而获取地址的范围空间,例如 32 位总线的寻址范围: 0~0xFFFF FFFF(4G)
  • Page Tabe: 页表, 虚拟地址空间和物理地址空间通过 page frame 来进行映射的, 页表还分为单页表(32 位 4G), 二级页表, 四级页表(64 位系统)
  • Virtual Memory Address: 在页表中的每一条记录都存储着页号物理页号的映射关系, 基于页表的记录记录的页号 + 偏移量就能找到虚拟内存地址映射的实际物理地址

内存术语

Swap

当物理内存空间不足的时候, 需要将哪些”占着茅坑不拉屎”的内存空间临时存在到某个地方, 哪个地方就是”swap”, 伴随着 swap-out, swap-in 的操作. 例如, 使用 Window 系统的时候, 当将一个长时间最小化的占用大量内存的应用程序调到前台时, 会发现磁盘在快速的进行读取操作, 就是在进行 swap-in 的操作, 此时会发现该程序切换到前台时会有一个卡顿的操作, 此时就是将 swap 的数据重新加载到内存中. 但是 swap 的分配也不是越大越好:

  • 如果 swap 分配太少, 当 swap 耗尽时, 会报”application is out of memory”错误.
  • 如果 swap 交换区数量少, 可能增加 IO 负载.
  • 如果实际场景中需要 swap 内存的值很大, 那说明应该增加的是物理内存而非 swap, 此时增加的 swap 值也是浪费以及影响服务器性能

所以, 一般按照公式swap size == mem size * 2/2.5进行 swap 的空间分配. 我们可以通过vmstat查看swap in/out的频率, 其中swap in/out的说明如下:

  • swap in: 进程需要 swap 中的数据而且此时物理内存空闲时, 会将 swap 中的需要的数据交换回物理内存中
  • swap out: 进程发现内存不足时, 会将内存中暂时没有使用到的数据(例如打开的文件)交换出去, 放到 swap 分区中. 若是发现 swap 空间也不足则 OS 会触发OOM-killer机制, 直接将消耗内存最多的进程 kill.

关于 swap 的详细信息见下方以及第四章 free 命令说明.

top 输出

关于 top 命令输出的详细信息见内存监控命令说明, 这里仅仅做一个知识点补充.

  1. VIRT
    Virtual memory usage 表示应用或进程占有的地址空间或虚拟内存总量, 应用程序申请的内存全算在这里, 此时 VIRT 的值等于代码段 + 栈 + 堆申请的所有内存空间. 例如, Process-A 申请 100M 内存, 实际使用 10M, 则 VIRT 值是 100M 而非实际使用的 1M, 下面是 top 命令下某个 celery 进程的输出信息:
1
2
进程号 USER      PR  NI    VIRT    RES    SHR    %CPU  %MEM     TIME+ DATA     COMMAND
3805 upps 20 0 1254472 132176 34868 S 0.7 0.8 3:39.97 449904 celery

其中, 进程实际使用内存为 130MB, 值等于 RES, RES 的值还等于总内存 * %MEM值, 但是 VIRT 的值却到达 1225MB, VIRT 值大概等价于SHR + mapped pags + swap out pages + etc.

  1. RES

Resident memory usage 表示常驻内存, 一个进程正在使用的空间, 只要对内存进行修改操作(例如 memset), 就会发生 RES 的增加动作. 常驻内存 = 进程在VIRT的内存空间中进行更改操作的那块内存空间, 不包含Swap out但包含Shared Memory. RES is most close to the memory used by the process in memory.
例如, 如果 Process-B 申请 200M 内存, 实际使用 1M, 则 RES 的值仍然是 1M, 而非 VIRT 中的 200M.

  1. SHR

Shared memory 表示共享内存(见 APUE 中 IPC 章节的介绍), 其表示多个进程可以共享的内存空间, 共享内存也是进程间通信的方式之一. SHR 的值等价为当前进程正在使用的共享内存空间, 某个进程独立占用物理内存大小: RES-SHR.
另外, 这里需要简单的说明下动态链接库和共享内存之间的区别, 免得产生歧义:

  • 动态链接库采用延时加载机制, 在内存中动态链接库确实只有一份, 其他进程在使用该动态库的时候会共享代码相关的内存, 但是在使用动态链接库期间所分配的内存都是进程自身独有的, 此数据内存并非共享内存.
  • 共享内存是一个广泛的概念, 其包含了动态链接库在内存中的独立一份的代码相关共享内存, 也包含了开发过程中为了进程间通信而分配的共享内存
  1. DATA

数据占用的内存, 如果 top 没有显示, 按 f 键然后选择 DATA(空格键), 最后按下右方向键选择就可以移动显示位置了. 该值是真正的该程序要求的数据空间, 是真正在运行中要使用的. 该值一般等价于栈 + 堆的总内存空间.

  1. SWAP

交换的内存来自虚拟内存, 该值一般等价于(栈 + 堆 + 共享内存)没有使用的内存空间.

  1. MEM

实际使用的物理内存大小.

macos

  • Wired Memory: 系统核心内存, 永远不会释放, 类似 Windows
  • Active Memory: 正在使用的内存
  • Inactive Memory: 已经分配,但是未使用的内存
  • Free: 可分配的内存

free 命令

  1. 命令输出

我们以free -m命令的输出再简单的了解一下 swap 以及内存相关知识:

1
2
3
              total        used        free      shared  buff/cache   available
Mem: 15810 11015 288 133 4505 2891
Swap: 8191 2965 5226

若希望输出更加人性化, 可以使用free -h查看输出, 其中各个字段含义:

  • total: 系统总的可用物理内存, 系统总的可用交换空间
  • used: 系统已使用的物理内存, 系统已使用的交换空间
  • free: 系统可分配的物理内存, 系统空闲的交换空间
  • shared: 被共享使用的物理内存
  • buff/cache: 被 buff 和 cache 使用的物理内存大小
  • available: 可以被应用程序使用的物理内存大小

其中 buff(缓冲区)和 cache(页高速缓存)已经在 1.1,1.2 节说明, 这里简单的介绍下 free 和 avaiable 两个字段的区别

  • free 表示真正尚未被使用的物理内存
  • available 表示从应用程序角度视角可以使用的内存, 即available ~= free + buffer + cache

free 命令的输出都是来源于/proc/meminfo文件, 这是 unix 系统上好多命令的类似做法, 只不过直接看文件中的输出信息可能不太直观, 通过命令查看更加直观清晰.

  1. Actual Used and Logical Used
  • buffers/used: used - buffers - cached == 实际使用的物理内存
  • buffers/used: free + buffers + cached == 理论上剩余可以使用的内存空间

其整体的计算公式: total == actual used + logical used

swap 增加

对于一些小型服务器, 特别是买来的 VPS, 因为囊中羞涩, 一般内存只有 850M 左右, 此时安装某些软件的时候会提示内存不足或者安装进度停止不前. 当然, 理论上, 什么设备干什么事情, 你干嘛要在一个 850M 内存机器上安装这么耗内存的应用呢? 为了中二少年的不切实际的幻想, 这里需要用到 swap, 确保软件能够正常安装. 下面是 swap 增加需要用到的一些命令或知识点:

  1. Check Swap Information
1
2
3
4
5
6
# 1. 查看缓冲区状态(最好在root用户下)
swapon --show
# 2. 显示交换分区简要信息
swapon -s
# 3. 查看内存
free -h
  1. Check Available Space on the Hard Drive Partition, 查看/dev/目录下各个设备的文件节点.
1
df -h
  1. Create A Swap File, 创建 SWAP 文件
1
2
3
4
# 使用fallocate创建, 如果没有权限, 则使用dd来创建
sudo fallocate -l 1G /swapfile
# 使用dd替代
dd if=/dev/zero of=/swapfile bs=4096 count=512k

4 add and enable Swap File

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 新增
sudo mkswap /swapfile
sudo swapon /swapfile

# 2. 如果已存在缓存, 则在更改/swapfile大小的前提下, 需要先关闭在刷新
sudo swapoff /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 3. 查看swap
sudo swapon --show
df -h
  1. Make the Swap File Permanent
1
2
sudo cp /etc/fstab /etc/fstab.bak
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
  1. 关闭
1
2
3
4
5
# 1. 关闭所有分区
swapoff -a

# 2. 关闭某个分区
swapoff -v /swapfile
  1. swappiness

swappiness 是内核参数, 用以控制 swap 的相对权重或者 swap 优先级, 其值一般在 0 和 100 之间, 值越低的内核会越少使用 swap, 默认值一般为 60, 此时一般不建议更改.

1
2
3
4
5
6
7
# 1. 查看当前系统的swappiness值
sysctl -q vm.swappiness
# 2. 临时更改
echo 30 > /proc/sys/vm/swappiness

# 3. 永久更改, 编辑/etc/sysctl.conf, 增加
vm.swappiness = 30

参考