Linux 内存是怎么工作的?

回答·9
最热
最新
  • 首先 linux 内存是 linux 服务器重要的组件之一,它的作用有的时候比硬盘和显卡都重要,在 linux 中 CPU 发出的各种指令都会与内存打交道,CPU——>控制单元——>算数单元——内存——外部存储还有输出单元和输入单元他们是电脑的组成。其次,如果用户发出指令那么 linux 就会通过控制单元和逻辑单元的判断在内存中找到相应的指令打开相应的进程和线程。如果当运行的应用程序过多可能会导致内存溢出,那么此时就会有 swap 分区,为什么呢?这是因为为了系统的运行不出现因内存不足导致服务器宕机或卡顿而设计的一种解决方案。
  • 去百度一下看看,这个需要了解吗?
  • 可以看看操作系统的五大管理之一,内存管理。
  • 只有内核才可以访问物理内存 而虚拟内存是运营软件和程序是 内存映射,其实就是将虚拟内存地址映射到物理内存地址。为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟地址与物理地址的映射关
  • 调用 c 标准库的都是用户空间的调用,用户空间的内存分配都是基于 buddy 算法(伙伴算法),并不涉及 slab
  • Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样进程就可以访问内存。
  • 虚拟内存映射物理内存
  • 大多数计算机的内存都是动态随机访问内存(DRAM)。只有内核才可以直接访问物理内存。 Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样,进程就可以很方便地访问内存,更确切地说是访问虚拟内存。虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同字长(也就是单个 CPU 指令可以处理数据的最大长度)的处理器,地址空间的范围也不同。 MMU 并不以字节为单位来管理内存,而是规定了一个内存映射的最小单位,也就是页,通常是 4 KB 大小。这样,每一次内存映射,都需要关联 4 KB 或者 4KB 整数倍的内存空间。 TLB(Translation Lookaside Buffer,转译后备缓冲器)会影响 CPU 的内存访问性能, TLB其实就是 MMU 中页表的高速缓存。由于进程的虚拟地址空间是独立的,而 TLB 的访问速度又比 MMU 快得多,所以,通过减少进程的上下文切换,减少 TLB 的刷新次数,就可以提高 TLB 缓存的使用率,进而提高 CPU 的内存访问性能。 页的大小只有 4 KB ,导致的一个问题就是,整个页表会变得非常大。比方说,仅 32 位系统就需要 100 多万个页表项(4GB/4KB),才可以实现整个地址空间的映射。为了解决页表项过多的问题,Linux 提供了两种机制,也就是多级页表和大页(HugePage)。 用户空间内存,从低到高分别是五种不同的内存段。只读段,包括代码和常量等。数据段,包括全局变量等。堆,包括动态分配的内存,从低地址开始向上增长。文件映射段,包括动态库、共享内存等,从高地址开始向下增长。栈,包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是 8 MB。在这五个内存段中,堆和文件映射段的内存是动态分配的。 malloc() 是 C 标准库提供的内存分配函数,对应到系统调用上,有两种实现方式,即 brk() 和 mmap()。小块内存(小于128KB)用brk()在堆段上分配,使用完之后不会立即归还系统,而是会缓存起来,供重复使用。大块内存(大于128KB)用mmap()在文件映射段,分配一块内存出来。两种实现方式的优缺点如下:brk() 方式的缓存,可以减少缺页异常的发生,提高内存访问效率。不过,由于这些内存没有归还系统,在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片。//造成内存碎片会怎样?mmap() 方式分配的内存,会在释放时直接归还系统,所以每次 mmap 都会发生缺页异常。在内存工作繁忙时,频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大。这也是 malloc 只对大块内存使用 mmap 的原因。(了解这两种调用方式后,我们还需要清楚一点,那就是,当这两种调用发生后,其实并没有真正分配内存。这些内存,都只在首次访问时才分配,整体来说,Linux 使用伙伴系统来管理内存分配。前面我们提到过,这些内存在 MMU 中以页为单位进行管理,伙伴系统也一样,以页为单位来管理内存,并且会通过相邻页的合并,减少内存碎片化(比如 brk 方式造成的内存碎片)。 实际系统运行中,确实有大量比页还小的对象,如果为它们也分配单独的页,那就太浪费内存了。所以,在用户空间,malloc 通过 brk() 分配的内存,在释放时并不立即归还系统,而是缓存起来重复利用。在内核空间,Linux 则通过 slab 分配器来管理小内存。你可以把 slab 看成构建在伙伴系统上的一个缓存,主要作用就是分配并释放内核中的小对象。 回收缓存,比如使用 LRU(Least Recently Used)算法,回收最近使用最少的内存页面;回收不常访问的内存,把不常用的内存通过交换分区直接写到磁盘中;杀死进程,内存紧张时系统还会通过 OOM(Out of Memory),直接杀掉占用大量内存的进程。 OOM(Out of Memory),其实是内核的一种保护机制。它监控进程的内存使用情况,并且使用 oom_score 为每个进程的内存使用情况进行评分:一个进程消耗的内存越大,oom_score 就越大;一个进程运行占用的 CPU 越多,oom_score 就越小。这样,进程的 oom_score 越大,代表消耗的内存越多,也就越容易被 OOM 杀死,从而可以更好保护系统。当然,为了实际工作的需要,管理员可以通过 /proc 文件系统,手动设置进程的 oom_adj ,从而调整进程的 oom_score。oom_adj 的范围是 [-17, 15],数值越大,表示进程越容易被 OOM 杀死;数值越小,表示进程越不容易被 OOM 杀死,其中 -17 表示禁止 OOM。比如用下面的命令,你就可以把 sshd 进程的 oom_adj 调小为 -16,这样, sshd 进程就不容易被 OOM 杀死。