Linux内存管理

简介: Linux内存管理

引言


根据上一节[[010104 - 存储层次]]介绍可以了解到系统分为寄存器,高速缓存,内存,外部存储,这几个组件的传输都比较简单易懂,其中我们会发现内存发挥了至关重要的作用,因为无论是高速缓存还是寄存器,他们提供的性能提升终究有限,如果所有的处理交给高速缓存和寄存器,那么成本和造价都是难以预估的。 所以针对内存的管理才是Linux核心和关键所在。


简单介绍



下面我们就来简单介绍Linux内存管理的,在Linux中内存管理可以大致理解为三个部分:

  • 内核使用的内存
  • 进程使用的内存
  • 可用内存(空闲内存)

其中除开内核使用的内存维持系统正常运行不能被释放之外,其他均可以由操作系统自由支配。


在Linux中拥有free命令来专门查看内存的使用情况,执行的效果类似如下:


/opt/app/tdev1$free
             total       used       free     shared    buffers     cached
Mem:       8175320    6159248    2016072          0     310208    5243680
-/+ buffers/cache:     605360    7569960
Swap:      6881272      16196    6865076


各个列的含义如下:

  • total:系统搭载物理内存总量,比如上面为8G
  • free:表面可用内存
  • buff/cache:缓冲区缓存和页面缓存,在[[010104 - 存储层次]]中提到了当内存不够的适合可以使用释放这两个缓存腾出空间给内存使用。
  • availiable:实际可以使用的内存,计算公式很简单 内核之外的可用总内存 - (free + buff/cache 最大可以释放的内存)。

除了列数据之外,可以看到还有一个swap的行数据,这个参数的含义将在后文进行介绍。

Linux除了free命令之外,还有sar -r命令,并且可以通过这个参数指定采集周期,比如-r 1就是1秒采集一次。

下面是这两个命令的对应关系:


  • total : 无对应
  • free :kbememfree
  • buff/cache :kbbufferrs + kbcached
  • available:无对应


如果内存使用过多,那么系统空出内存,可能会出现强制kill某个进程的操作,这个操作是随机的,无法被监控,如果是个人电脑也许还可以接受,但是如果是商用机器上这种操作就十分危险了,所以有部分的商用机器会开启一旦OO M直接把整个系统强制关闭的操作。

另外Mac系统虽然类Unix系统但是没有free相关的命令,为此可以使用下面的命令进行简单的替代,但是不如free强大。

比如在Mac中使用top -l 1 | head -n 10查看整体系统运行情况。


MacBook-Pro ~ % top -l 1 | head -n 10
Processes: 604 total, 2 running, 602 sleeping, 3387 threads 
2022/04/15 17:29:57
Load Avg: 2.84, 3.27, 5.68 
CPU usage: 6.8% user, 14.18% sys, 79.72% idle 
SharedLibs: 491M resident, 96M data, 48M linkedit.
MemRegions: 168374 total, 5515M resident, 235M private, 2390M shared.
PhysMem: 15G used (1852M wired), 246M unused.
VM: 221T vsize, 3823M framework vsize, 0(0) swapins, 0(0) swapouts.
Networks: packets: 312659/297M in, 230345/153M out.
Disks: 788193/14G read, 161767/3167M written.


比如在Mac中使用使用diskutil list


```shell
~ > diskutil list
/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         500.3 GB   disk0
   1:             Apple_APFS_ISC ⁨⁩                        524.3 MB   disk0s1
   2:                 Apple_APFS ⁨Container disk3⁩         494.4 GB   disk0s2
   3:        Apple_APFS_Recovery ⁨⁩                        5.4 GB     disk0s3
/dev/disk3 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +494.4 GB   disk3
                                 Physical Store disk0s2
   1:                APFS Volume ⁨mysystem⁩                15.2 GB    disk3s1
   2:              APFS Snapshot ⁨com.apple.os.update-...⁩ 15.2 GB    disk3s1s1
   3:                APFS Volume ⁨Preboot⁩                 529.6 MB   disk3s2
   4:                APFS Volume ⁨Recovery⁩                798.6 MB   disk3s3
   5:                APFS Volume ⁨Data⁩                    455.3 GB   disk3s5
   6:                APFS Volume ⁨VM⁩                      24.6 KB    disk3s6
/dev/disk6 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *512.1 GB   disk6
   1:       Microsoft Basic Data ⁨⁩                        512.1 GB   disk6s1
/dev/disk7 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk7
   1:       Microsoft Basic Data ⁨Extreme SSD⁩             1.0 TB     disk7s1


简单系统内存分配


内核分配内存的时机大致有下面两种:

  1. 第一种是创建进程的时候。
  2. 第二种是创建进程之后进行动态内存分配的时候。

在进程创建之后,如果进程还需要内核提供更多的内存,则可以向内核发出内存的请求申请,内核收到指令之后,则划分可用内存并且把起始结束的地址给进程进行使用。 但是这种要一点给一点的方式有下面几个常见的问题:


  • 难以执行多个任务。
  • 访问其他用途的内存区域。
  • 内存的碎片化。


内存不仅仅需要和CPU通信还需要和其他的控制器和硬件打交道,分配内存给进程只是诸多任务的项目之一。


难以执行多任务可以理解为进程频繁的需要申请内存的情况,这时候内核需要不断的操作分配内存给进程,整个任务被单个进程给拖累了。另外如果多个任务出现分配内存的区域刚好相同,此时需要要完成内存分配给那个进程,则另一个进程等待也是可以理解的。

内存碎片化的原因是进程每次获取内存都需要了解这部分内容要涵盖多少区域否则就不能获取这些内存。 内存碎片化的另一个重大问题是明明有很多富裕的内存但是却拿不出一块完整连续的空间给进程使用,导致不断的回收和分配操作。


虚拟地址和物理地址


首先我们需要了解三个名次的概念:地址空间、虚拟地址、物理地址。 地址空间:指的是可以通过地址访问的范围都统称为地址空间。 虚拟地址:虚拟地址指的是进程无法直接访问到真实的物理内存地址,而是访问和实际内存地址映射的虚拟内存地址,目的是为了保护系统硬件安全。 物理地址:也就是我们实际内存对应的实际的物理地址。 这里举一个简单的例子:如果内核给进程分配一个100地址的虚拟内存地址,那么这个虚拟内存地址可能会指向实际的600物理地址。

页表完成虚拟地址到物理地址的映射依靠的是页表,在虚拟内存当中所有的内存都被划分为页,一个页对应的数据条目叫做页表项,页表项记录物理地址到虚拟地址的映射关系。 在x86-64的架构当中,一个页的大小为4KB。上面提到了进程神奇的内存是有固定的起止地址的,那么如果出现超出地址的页访问,也就是访问了没有虚拟地址和物理地址映射的空间,会出现什么情况呢? 如果出现越界访问,那么此时CPU会出现缺页中断,并且终止在缺页中进行操作的进程指令,同时启动内核的中断处理机构处理。


虚拟内存的分配操作


虚拟内存的分配操作步骤我们可以理解为几个核心的步骤:

  • 内核寻找物理地址,并且把需要的物理地址空间计算之后,请求物理分页。
  • 创建进程的页表把物理地址映射到虚拟地址。
  • 如果进程需要动态内存管理,内核则会分配新页表并且分配新的可用内存给进程使用,当然同时提供对应的虚拟地址空间。

物理分页使用的是请求分页的方式进行处理,这个分配的操作十分复杂。


内存的上层分配

在经典的编程语言C语言中,分配内存的函数是malloc函数,而Linux操作系统中用于分配内存的函数是mmap函数,这两者最大区别是mmap函数使用的是按页的方式分配,而malloc是按照字节的方式分配。

glibc通过系统调用向mmap申请大量的内存空间作为内存池,程序调用malloc则根据内存池分配出具体的内存使用,如果进程需要再次获取内存则需要再次通过mmap获取内存并且再次进行分配操作。

其实更为上层的编程语言也是使用了类似的操作,首先通过glibc向内核申请内存执行虚拟内存的分配操作,然后malloc函数再去请求划分具体的内存使用,只不过更上层的语言使用了解析器和脚本进行掩盖而已,实际上通过层层翻译最终的操作依然是上面提到的操作。

虚拟内存是如何解决简单分配的问题的?这里我们再次把上面三个问题搬出来,再解释虚拟内存是如何处理问题的:


  • 难以执行多个任务:每个进程有独立的虚拟地址空间,所以可以编写专用地址空间程序防止多个任务阻塞等待的情况。
  • 访问其他用途的内存区域:虚拟地址空间是进程独有,页表也是进程独有。页表的另一个作用是限制可以防止当前的进程访问到其他线程的页表和地址空间。
  • 内存的碎片化:内存碎片化使用页表的方式进行分配,因为页表记录了物理地址到虚拟地址的映射,这样就可以很好的知道未使用的空间都干了啥。

虚拟内存的其他作用:

  • 文件映射
  • 请求分页
  • 利用写时复制的方式快速创建进程
  • 多级页表
  • 标准大页


小结


这一部分简要阐述Linux内存管理的入门理解部分,这一部分主要介绍了简要的内存分配方式,以及Linux对此通过页表的方式实现物理地址和虚拟地址的分配,最后阐述了操作系统和编程语言也就是进程之间是如何分配内存的,具体的分配步骤和交互逻辑介绍。

相关文章
|
8月前
|
缓存 Linux
linux 手动释放内存
在 Linux 系统中,内存管理通常自动处理,但业务繁忙时缓存占用过多可能导致内存不足,影响性能。此时可在业务闲时手动释放内存。
401 17
|
4月前
|
缓存 Linux 数据安全/隐私保护
Linux环境下如何通过手动调用drop_caches命令释放内存
总的来说,记录住“drop_caches” 命令并理解其含义,可以让你在日常使用Linux的过程中更加娴熟和自如。
977 23
|
10月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
2072 6
|
6月前
|
监控 Linux Python
Linux系统资源管理:多角度查看内存使用情况。
要知道,透过内存管理的窗口,我们可以洞察到Linux系统运行的真实身姿,如同解剖学家透过微观镜,洞察生命的奥秘。记住,不要惧怕那些高深的命令和参数,他们只是你掌握系统"魔法棒"的钥匙,熟练掌握后,你就可以骄傲地说:Linux,我来了!
223 27
|
7月前
|
消息中间件 Linux
Linux中的System V通信标准--共享内存、消息队列以及信号量
希望本文能帮助您更好地理解和应用System V IPC机制,构建高效的Linux应用程序。
262 48
|
7月前
|
缓存 NoSQL Linux
Linux系统内存使用优化技巧
交换空间(Swap)的优化 禁用 Swap sudo swapoff -a 作用:这个命令会禁用系统中所有的 Swap 空间。swapoff 命令用于关闭 Swap 空间,-a 参数表示关闭 /etc/fstab 文件中配置的所有 Swap 空间。 使用场景:在高性能应用场景下,比如数据库服务器或高性能计算服务器,禁用 Swap 可以减少磁盘 I/O,提高系统性能。
282 3
|
7月前
|
缓存 Linux
Linux查看内存命令
1. free free命令是最常用的查看内存使用情况的命令。它显示系统的总内存、已使用内存、空闲内存和交换内存的总量。 free -h • -h 选项:以易读的格式(如GB、MB)显示内存大小。 输出示例: total used free shared buff/cache available Mem: 15Gi 4.7Gi 4.1Gi 288Mi 6.6Gi 9.9Gi Swap: 2.0Gi 0B 2.0Gi • to
545 2
|
10月前
|
缓存 Java Linux
如何解决 Linux 系统中内存使用量耗尽的问题?
如何解决 Linux 系统中内存使用量耗尽的问题?
824 59
|
10月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
1374 58
|
10月前
|
缓存 Linux
如何检查 Linux 内存使用量是否耗尽?
何检查 Linux 内存使用量是否耗尽?
385 58