JohnShen's Blog.

Linux性能优化-内存篇

字数统计: 1.6k阅读时长: 5 min
2021/05/16 Share

1. 内存映射

虚拟内存:

Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。进程可以很方便地访问虚拟内存。

虚拟地址空间分为:内核空间和用户空间。不同字长处理器(32位/64位)地址空间范围也不同。进程在用户态时,只能访问用户空间内存;只有进入内核态后,才可以访问内核空间内存。

所有进程的虚拟内存加起来要比实际内存大得多,因此不是所有虚拟内存都分配内存,只有实际使用的虚拟内存才会分配物理内存,分配后的物理内存通过内存映射进行管理。内存映射,其实就是将虚拟内存地址映射到物理内存地址。为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟地址与物理地址的映射关系。当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行。

内存映射的最小单位为页,通常是4KB大小。4G内存需4G/4K=100多万页表项才能完成整个地址空间映射。为解决页表项过多的问题,Linux提供两种机制:多级页表和大页 (HugePage):

  • 多级页表:映射关系改为区块索引和区块内的偏移。Linux采用的是四级页表管理内存页,前四个页表项用于选择页,最后一个索引表示页内偏移。
  • 大页:更大的内存块,通常大小有2MB和1GB,通常应用在使用大量内存的Linux进程中。

2. 虚拟内存空间分布

内核空间和用户空间,其中用户空间包括:

  • 只读段,包括代码和常量等。

  • 数据段,包括全局变量等。

  • 堆,包括动态分配的内存,从低地址开始向上增长。

  • 文件映射段,包括动态库、共享内存等,从高地址开始向下增长。

  • 栈,包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是 8 MB。

堆和文件映射段的内存是动态分配的。比如说,使用 C 标准库的 malloc() 或者 mmap() ,就可以分别在堆和文件映射段动态分配内存。

3. 内存分配与回收

malloc() 是 C 标准库提供的内存分配函数,当进程通过 malloc() 申请内存后,内存并不会立即分配,而是在首次访问时,才通过缺页异常陷入内核中分配内存。

malloc() 对应到系统调用有两种实现方式: brk() 和 mmap()。

  • 小块内存(小于 128K),C 标准库使用 brk() 来分配,内存释放并不会立刻归还系统,而是被缓存起来重复使用。减少缺页异常的发生,提高内存访问效率,但频繁的内存分配和释放会造成内存碎片。
  • 大块内存(大于 128K),使用mmap() 来分配,在文件映射段找一块空闲内存分配出去。频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大

在应用程序用完内存后,还需要调用 free() 或 unmap() ,来释放这些不用的内存。

当有大量比页还小的的对象要分配时,为它们分配单独的页会浪费内存。因此,在用户空间,malloc() 通过 brk() 分配的内存,在释放时并不立即归还系统,而是缓存起来重复利用。在内核空间,Linux 则通过 slab 分配器来管理小内存,slab 主要作用就是分配并释放内核中的小对象。

4. 处理内存紧张

  • 回收缓存,比如LRU回收最近使用最少的内存页面。

  • 回收不常访问的内存,把不常用内存通过交换分区写入磁盘。

    • Swap 把系统的可用内存变大了。不过通常只在内存不足时才会发生 Swap 交换。由于磁盘读写的速度远比内存慢,Swap 会导致严重的内存性能问题。
  • 杀死进程,系统通过OOM直接杀掉占用大量内存的进程。

    • OOM是内核的一种保护机制,监控进程的内存使用,使用 oom_score 为每个进程的内存使用情况进行评分:进程消耗内存越大,oom_score 就越大;进程运行占用 CPU 越多,oom_score 就越小。

    • oom_adj 的范围是 [-17, 15],数值越大,表示进程越容易被 OOM 杀死;数值越小,表示进程越不容易被 OOM 杀死,其中 -17 表示禁止 OOM。

    • echo -16 > /proc/$(pidof sshd)/oom_adj以这种方式可以调整某进程的oom_adj。

5. 内存使用查看

查看系统内存使用

使用free命令时的各列含义:

  • total 总内存大小;

  • used 已使用内存的大小,包含了共享内存;

  • free 未使用内存的大小;

  • shared 共享内存的大小;

  • buff/cache 缓存和缓冲区的大小;

  • available 新进程可用内存的大小。available 不仅包含未使用内存,还包括了可回收的缓存,所以一般会比未使用内存更大。

查看进程内存使用

使用top时的内存相关列的含义:

  • VIRT 进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内。
  • RES 常驻内存的大小,也就是进程实际使用的物理内存大小。
  • SHR是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。SHR 并不一定是共享的,比方说,程序的代码段、非共享的动态链接库,也都算在 SHR 里。当然,SHR 也包括了进程间真正共享的内存。
  • %MEM 是进程使用物理内存占系统总内存的百分比。

理解virt res shr之间的关系 - linux

CATALOG
  1. 1. 1. 内存映射
  2. 2. 2. 虚拟内存空间分布
  3. 3. 3. 内存分配与回收
  4. 4. 4. 处理内存紧张
  5. 5. 5. 内存使用查看
    1. 5.1. 查看系统内存使用
    2. 5.2. 查看进程内存使用