首先我们8g的内存,其实指的是物理内存,也就是主存,
在Linux系统里边,我们的进程是不能直接访问物理内存的,它会为每个进程分配一个虚拟地址内存,然后通过虚拟地址内存去访问,
在CPU的内存管理单元里边有一个页表,它会把我们的虚拟内存跟物理内存之间做一个映射,
只有那些实际使用的虚拟内存才会分配物理内存,也就是提供一个内存映射的关系
当进程访问的虚拟地址在列表中查不到的时候,就会产生一个缺页异常,然后就会重新分配物理内存,然后更新页表,再返回给用户空间,这样进程就恢复正常
内存映射的最小单位是页,这个页一般是比较小的,一般是4kb左右,
它页比较小,就有一个问题,因为这个页比较小,所以需要比较多的页才能提供这个内存映射的关系,所以整个页表会变得非常大,
那么里面为了解决这个页表变得非常大的问题,Linux有两种机制,一个是多级页表,一个是大页,
Linux的多级页表采用的是4级页表,它通过将原来的映射关系,改成区块索引以及区块内的偏移,
因为虚拟内存空间通常只用到了很少的一部分,多级页表就只保存这些用到的虚拟内存,这样就可以减少那个页表的数量,
还有一种机制是大页,也就是分配比一般的页更大的页,常见的有2MB,1GB,大页通常用在那些使用大量内存的进程上,比如 Oracle,还有es,logstash他们占用的内存也挺多的,
malloc() 是 C 标准库提供的内存分配函数,对应到系统调用上,有两种实现方式,即 brk() 和 mmap()。
对小块内存(小于 128K),C 标准库使用 brk() 来分配,也就是通过移动堆顶的位置来分配内存。这些内存释放后并不会立刻归还系统,而是被缓存起来,这样就可以重复使用。
而大块内存(大于 128K),则直接使用内存映射 mmap() 来分配,也就是在文件映射段找一块空闲内存分配出去。
brk() 方式的缓存,释放后不会立即归还给系统,可以减少缺页异常的发生,提高内存访问效率。当时,因为这些内存没有归还系统,所以在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片。
而 mmap() 方式分配的内存,会在释放时直接归还系统,所以每次 mmap 都会发生缺页异常。在内存工作繁忙时,频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大。这也是malloc 只对大块内存使用 mmap 的原因
。
对内存来说,如果只分配而不释放,就会造成内存泄漏,甚至会耗尽系统内存。所以,在应用程序用完内存后,还需要调用 free() 或 unmap() ,来释放这些不用的内存
在发现内存紧张时,系统也有一系列机制来回收内存,
LRU
(least Recently Used)算法,对那些最近最少使用的的内存页面进行回收swap交换分区
Swap 把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用。再次访问这些不常访问的内存的时时候,重新从磁盘读入内存就可以了。
简单来说,Swap 说白了就是把一块磁盘空间或者一个本地文件(以下讲解以磁盘为例),当成内存来使用。它包括换出和换入两个过程
swap它把我们系统的可用内存变大了,但是因为硬盘比内存慢得多,所以如果swap被大量使用了,就要进一步排查。
平时我们笔记本电脑休眠的时候,利用的就是swap的原理,休眠时,把系统的内存存入磁盘,这样等到再次开机时,只要从磁盘中加载内存就可以。这样就省去了很多应用程序的初始化过程,加快了开机速度。
swap是用来回收内存的,对于回收内存,最容易想到的场景就是有一个新的大块内存需要分配,但是现在内存不够,这时候就需要回收一部分内存,它被称为直接内存回收
另外,还有一个专门的内核线程用来定期回收内存,叫kswapd0。kswapd0 定义了三个内存阈值(watermark,也称为水位),分别是
页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high)。剩余内存,则使用 pages_free 表示。
另外,也有可能出现可用内存还有很多,但是swap被使用得也很多。可能是因为一些进程的内存占用比较大,所以占用了swap内存,但是当这个进程结束的时候,它的可用内存就恢复得比较大了。但是由于之前他占用了交换分区,交换分区里面的内存还没有放到可用内存里边,还是放在磁盘里边的,所以就会造成这种情况发生。
free
[root@VM_0_11_centos ~]# free
total used free shared buff/cache available
Mem: 1882056 385240 78224 624 1418592 1308716
Swap: 0 0 0
最后一列的可用内存 available 。available 不仅包含未使用内存,还包括了可回收的缓存。但是,并不是所有缓存都可以回收,因为有些缓存可能正在使用中。
free 显示的是整个系统的内存使用情况。如果你想查看进程的内存使用情况,使用 top
[root@VM_0_11_centos ~]# top
top - 20:22:42 up 25 days, 5:36, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 90 total, 2 running, 88 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1882056 total, 74196 free, 385740 used, 1422120 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1308224 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 191040 2852 1408 S 0.0 0.2 4:43.55 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd
4 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
6 root 20 0 0 0 0 S 0.0 0.0 0:32.51 ksoftirqd/0
在free命令里面其他指标都很好理解,然后有个buffer和cache,它的字面意识是buffer是缓冲,cache是缓存,之前我man free去查看过他的定义,
buffers
Memory used by kernel buffers (Buffers in /proc/meminfo)
cache Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
buff/cache
Sum of buffers and cache
他的帮助手册里面显示:
它的帮助手册里面告诉我们,这些数值都来自 /proc/meminfo
。实际上,很多的性能分析工具,他们的数据都是从/proc/这个目录里面获取的。所以我们可以继续man
一下proc目录,
它这里的定义是
磁盘的数据
,通常只有20兆左右,它是用来优化数据写入磁盘的,可以把多次分散的写集中起来,统一成一次来写入,。缓存从文件读取的数据
。这样,下次访问这些文件数据时,就可以直接从内存中快速获取,而不需要再次访问缓慢的磁盘。Buffer 的文档没有提到这是磁盘读数据还是写数据的缓存,而在很多网上资料里面,都会提到 Buffer 只是对将要写入磁盘数据的缓存
文档中提到,Cache 是对从文件读取数据的缓存,那么它是不是也会缓存写文件的数据呢?
我之前使用dd
命令分别进行磁盘和文件的写和读的实验,然后开另一个终端用vmstat来观察,发现:
简单来说,Buffer 是对磁盘数据的缓存,而 Cache 是文件数据的缓存,它们既会用在读请求中,也会用在写请求中。