- 内存需要被分成固定大小的页,然后再通过虚拟内存地址到物理内存地址的地址转换,才能到达实际存放数据的物理内存位置。
- 程序看到的内存地址,都是虚拟内存地址,这些虚拟内存还需要通过页表,由系统映射为物理内存。
- 当进程通过 malloc() 申请虚拟内存后,系统并不会立即为其分配物理内存,而是在首次访问时,才通过
缺页异常
陷入内核中分配内存。 - 在内存资源紧张时,Linux 通过
直接内存回收
和定期扫描
的方式,来释放文件页
和匿名页
,以便把内存分配给更需要的进程使用。
- 在 CPU 里放了一块缓存芯片,称之为 TLB,全称是
地址转换查找缓冲(Translation Lookaside Buffer)
。 - 这块缓存存放了之前已经进行过地址转换的查询结果。当同样的虚拟地址需要进行地址转换的时候,可以直接在 TLB 里面查询结果,而不需要多次访问内存来完成一次转换。
- Buffer 是磁盘设备的缓存。
- Cache 是文件系统的缓存。
- 读写块设备文件时,会跳过文件系统,直接与磁盘交互,也就是所谓的"
裸 I/O
"。
- 根据是否利用
标准库缓存
,可以把文件 I/O 分为缓冲 I/O 与非缓冲 I/O。- 缓冲 I/O 是指利用标准库缓存来加速文件的访问,而标准库内部则通过系统调度访问文件。
- 非缓冲 I/O 是指直接通过系统调用来访问文件,不在经过标准库缓存。
- 根据是否利用操作系统的
页缓存
,直接跟文件系统交互来访问文件。- 直接 I/O(裸 I/O)是指跳过操作系统的页缓存,直接跟文件系统交互来访问文件。
- 非直接 I/O 先要经过系统的页缓存,然后再由内核或额外的系统调用,真正写入磁盘。要想实现直接 I/O ,需要在文件系统调用中,指定
O_DIRECT
标志,如果没有设置过,默认是非直接 I/O。
- 根据应用程序是否
阻塞自身
运行,可以把文件 I/O 分为阻塞 I/O 和非阻塞 I/O。- 阻塞 I/O 是指应用程序执行 I/O 操作后,如果没有获得响应,就会阻塞当前线程。
- 非阻塞 I/O 是指应用程序执行 I/O 操作后,不会阻塞当前的线程,可以继续执行其他的任务,随后再通过轮询或者事件通知的形式,获取调用的结果。访问管道或者网络套接字时,设置
O_NONBLOCK
标志,就表示用非阻塞方式访问;而如果不做任何设置,默认的就是阻塞访问。
- 根据是否
等待响应结果
,可以把文件 I/O 分为同步和异步 I/O。- 同步 I/O 是指应用程序执行 I/O 操作后,要一直等到整个 I/O 完成后,才能获得 I/O 响应。
- 异步 I/O 是指应用程序执行 I/O 操作后,不用等待完成和完成后的响应,而是继续执行就可以。等到这次 I/O 完成后,响应会用事件通知的方式告诉应用程序。在操作文件时,如果设置了
O_SYNC
或者O_DSYNC
标志,就代表同步 I/O。如果设置了O_DSYNC
,就要等文件数据写入磁盘后,才能返回;而 O_SYNC,则是在 O_DSYNC 基础上,要求文件元数据也要写入磁盘后,才能返回。在访问管道或者网络套接字时,设置了O_ASYNC
选项后,相应的 I/O 就是异步 I/O。这样,内核会再通过SIGI/O
或者SIGPOLL
,来通知进程文件是否可读写。
- Swap 把磁盘空间当成内存来用,把进程暂时不用的数据存储到磁盘中(换出),当进程访问这些内存时,再从磁盘读取这些数据到内存中(换入)。
- 对匿名页的回收,其实就是通过 Swap 机制,把它们写入磁盘后再释放内存。
- 由于磁盘读写的速度远比内存慢,Swap 会导致严重的内存性能问题。
- Linux 提供了一个
/proc/sys/vm/swappiness
选项,用来调整使用 Swap 的积极程度。swappiness=0,表示最大限度使用物理内存,然后才是 swap 空间。swappiness=100,表示积极的使用 swap 分区。 swapoff -a
命令关闭 SWAP,swapon -a
命令打开 SWAP。- 在开启 Swap 的服务器中运行,可以用库函数
mlock()
或者mlockall()
锁定内存,阻止它们的内存换出。
NUMA(非一致性内存访问)
是一种计算机体系结构设计,用于处理多个处理器(CPU)访问共享内存的问题。- 在 NUMA 架构中,每个处理器都有自己的本地内存,访问本地内存的速度比访问远程内存要快。因此,NUMA 可以提高多处理器系统的性能。
- 在 NUMA 架构下,每个 Node 都有自己的本地内存空间,而当本地内存不足时,默认既可以从其他 Node 寻找空闲内存,也可以从本地内存回收。
- 可以设置
/proc/sys/vm/zone_reclaim_mode
,来调整 NUMA 本地内存的回收策略。#0 默认值,在回收本地内存之前,在其他 Node 寻找空闲内存 #1 只回收本地内存 #2 只回收本地内存,在本地回收内存时,可以将文件页中的脏页写回硬盘,以回收内存 #4 只回收本地内存,在本地回收内存时,可以用 swap 方式回收内存
- DMA 技术,就是直接内存访问(Direct Memory Access)技术,来减少 CPU 等待的时间。
- 本质上,DMA 技术就是在主板上放一块独立的芯片。在进行内存和 I/O 设备的数据传输的时候,不再通过 CPU 来控制数据传输,而直接通过 DMA 控制器(DMA Controller,DMAC)。这块芯片其实就是一个协处理器(Co-Processor)。
- DMAC 最有价值的地方体现在,当要传输的数据特别大、速度特别快,或者传输的数据特别小、速度特别慢的时候。比如,用千兆网卡或者硬盘传输大量数据时,如果都用 CPU 来搬运的话,肯定忙不过来,所以可以选择 DMAC。而当传输很慢的时候,DMAC 可以等数据到齐了,再发送信号,给到 CPU 去处理,而不是让 CPU 在哪里忙等。
- Buffers 和 Cache 可以极大提升系统的 I/O 性能。
- 用缓存命中率,来衡量缓存的使用效率。命中率越高,表示缓存被利用得越充分,应用程序的性能也就越好。
- 禁止 Swap。如果必须开启 Swap,降低
swappiness
的值,减少内存回收时 Swap 的使用倾向。 - 减少内存的动态分配。比如,可以使用内存池、大页(HugePage)等。
- 尽量使用缓存和缓冲区来访问数据。比如,可以使用堆栈明确声明内存空间,来存储需要缓存的数据;或者用 Redis 这类的外部缓存组件,优化数据的访问。
- 使用
cgroups
等方式限制进程的内存使用情况。这样,可以确保系统内存不会被异常进程耗尽。 - 通过
/proc/pid/oom_adj
,调整核心应用的oom_score
。这样,可以保证即使内存紧张,核心应用也不会被 OOM 杀死。
- oomkill[-bpfcc/.bt]
- memleak[-bpfcc]
- shmsnoop[-bpfcc]