我们买电脑的参数8GB,是指物理内存,而只有内核才能直接访问物理内存,那么进程访问内存要如果做?
虚拟存储器(内存)的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。 为了更好的管理内存,操作系统将内存抽象成地址空间。每个进程拥有自己的地址空间,这个地址空间是连续的,这个地址空间被分割成多个块,每一块称为一页。也就是说,进程可以很方便访问内存,更确切是访问虚拟内存。
每个进程都有这么大的地址空间,那么所有进程的虚拟内存加起来,要比实际内存大很多。但是,并不是所有的虚拟内存都会分配物理内存,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存。内存映射,其实就是讲虚拟内存地址映射到物理内存地址,内核为每个进程维护一张页表,记录虚拟地址和物理地址的映射关系
页表实际存储在CPU的内存管理单元MMU中,这样处理器就可以直接通过硬件,找出要访问的内存
当进程访问的虚拟地址在页表中查不到,产生却缺页异常,进入内核空间分配物理内存,更新进程页表,最后返回用户空间,恢复进程运行
不过要注意,MMU并不以字节为单位来管理内存,而是规定内存映射最小单位页的大小通常为4KB,会导致页表项过多。比如32位系统需要100多万个页表项(4G/4k)才能实现整个地址空间映射
所以使用多级页表和大页(hugepage)解决页表项过多
Linux使用使用四级页表来管理内存页。虚拟地址分为五个部分,前四个表项用于选择页,最后一个索引表示页内偏移
每个进程都拥有一个自己的页表,在linux中,有一个页目录数组,这是分页机制的最高层,每个进程的页表对应其中的一个页目录项
32位系统的两极分页:两级表的第一级表称为页目录,存储在一个4K字节的页中,页目录表共有1K个表项,每个表项为4个字节,线性地址最高的10位(22-31)用来产生第一级表索引,由该索引得到的表项中的内容定位了二级表中的一个表的地址,即下级页表所在的内存块号。
第二级表称为页表,存储在一个4K字节页中,它包含了1K字节的表项,每个表项包含了一个页的物理地址。二级页表由线性地址的中间10位(12-21)位进行索引,定位页表表项,获得页的物理地址。页物理地址的高20位与线性地址的低12位(偏移offset)形成最后的物理地址。
用户空间内存,也分成了多个不同的段
其中,堆和文件映射段的内存是动态分配的,比如使用C标准库的malloc()或者mmap()。
然而,这两种调用发生是,并没有真正分配内存,而是在首次访问时,才通过缺页异常陷入内核中分配内存。
在内核空间,通过slab分配器来管理小内存
发现内存紧张时,系统会通过一系列机制来回收内存,比如如下三种机制:
其中第三种方式OOM,是一种内核的保护机制,使用oom_score为每个进程的内存使用情况进行评分。管理员可以通过/proc文件系统,手动设置进程oom_adj,从而调整进程的oom_score。
free命令的最终来源是/proc/meminfo。
A buffer is something that has yet to be “written” to disk.
A cache is something that has been “read” from the disk and stored for later use.
比如你每秒要写100次硬盘,对系统冲击很大,浪费了大量时间在忙着处理开始写和结束写这两件事嘛。用个buffer暂存起来,变成每10秒写一次硬盘,对系统的冲击就很小。
Cache的核心作用是加快取用的速度。比如你一个很复杂的计算做完了,下次还要用结果,就把结果放手边一个好拿的地方存着,下次不用再算了。加快了数据取用的速度。
Cache是内核页缓存和Slab用到的内存,对应的是/proc/meminfo中的cached和SReclaimable。Buffer是对磁盘(块设备文件)数据的缓存,Cache是文件(普通文件)数据的缓存,既会用在读请求,也会用在写请求中。读写普通文件,会经过文件系统,由文件系统负责与磁盘交互。而读写磁盘或者分区,跳过文件系统直接操作disk,“裸IO”(Direct IO),他们使用的缓存是不同的。
实例:
1.通过读取随机设备,生成一个500MB大小文件
dd if=/dev/urandom of=/tmp/file bs=1M count=500
dd可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。
- if=文件名:输入文件名,缺省为标准输入。即指定源文件。
- of=文件名:输出文件名,缺省为标准输出。即指定目的文件。
/dev/random和/dev/urandom是Linux系统中提供的随机伪设备,这两个设备的任务,是提供永不为空的随机字节数据流。
通过vmstat观察输出,可以看到Cache不断增长,而Buffer基本不变。说明写文件时会用到Cache缓存数据
2.向磁盘写入随机数据
dd if=/dev/urandom of=/dev/sdb1 bs=1M count=2048
这里Buffer增长很明显
3。从文件读取数据写入空设备
dd if=/tmp/file of=/dev/null
通过vmstat,发现读取文件(bi大于0)Buffer基本不变,而Cache在不停的增长
4.从块设备磁盘中读取数据
dd if=/dev/sda1 of=/dev/null
这里Buffer增长很明显,说明读磁盘时,数据缓存到了Buffer中,解决了存储速度不同步的设备问题,