free
\ | total | used | free | shared | buffers | cached |
---|---|---|---|---|---|---|
Mem | 3908800 | 1149620 | 2759180 | 0 | 53744 | 866408 |
-/+ buffers/cache | 229468 | 3679332 | ||||
Swap | 3145720 | 0 | 3145720 |
Line 1 : 指出了内存使用的情况,比如 总量、可用、已用、共享、buffer使用的内存、cache使用的内存(磁盘cache)
Line 2 : 指出了 buffer/Cache 已用与可用
Line 3 : 指出了交换区可用的内存,展示出了已用和可用交换区内存大小
Line 1
- 3908800 指出了该机器有多少物理内存(单位KB)
- 1149620 指出了系统已经使用了多少内存(这个大小包括 cache 与 buffer)
- 2759180 指出了还有多少内存可以使用(与代表一个新程序最多还能使用多少内存)
- 0 它指出了共享内存,这列如今没什么用了,未来free 命令可能废除这列
- 53744 指出了在Linux下的所有程序共使用了多少内存当作buffer
- 866408 指出了多少内存用来当做磁盘的cache
buffer 与 cache
Buffer 是临时用来存数据的空间。当你尝试发送大量的数据往网络上的时候,如果你的网卡网速很低,没办法大量的发送数据,那么将会有大量的数据被滞留在buffer中以此来不断地慢慢地降低网速(减少访问硬件的频率)。所以它实际上是硬件设备的缓冲区。
另一方面Cache是用来保存不断被使用到的数据的一个区域,它主要是为了提高访问数据的速度。所以它实际上就是操作系统的内核缓冲区,比如read系统调用时就是内核缓冲区中的数据读取到应用层。
buffer与cache不通的点主要在于cache中的数据会被多次使用而buffer保存的数据只使用一次。这个就像我们平常调用read/write函数,这些磁盘上的数据就被加载到内存,那么操作系统会预读更多的数据到cache中,那么当我们下次调read/write函数顺序读取的时候不用再去磁盘读取了,这样大大的提高了访问数据的速度。而对于buffer来说,一般都是用来刷新到硬件上的数据,它被刷完之后就会被抛弃,所以只使用一次。
文件Cache作用
buffer 与 cache 都属于文件cache。文件Cache的管理与内存管理系统和文件系统都息息相关。首先,Cache作为内存的一部分,需要参与内存的分配与回收,那么这个过程是由内存管理系统去负责的。其次,文件Cache的数据都来自于硬件,它需要与硬件进行读写交互,所以需要用文件系统使用文件Cache与硬件交互数据。所以,文件Cache可以看做是内存管理系统与文件系统之间的沟通桥梁,所以文件Cache管理也是操作系统一个重要组成部分。
文件Cache 相关结构
从逻辑上讲文件Cache区分为PageCache 与 BufferCache,但是本质上BufferCache是属于PageCache的一种。每一个PageCache都包含了若干个BufferCache ,PageCache通过buffer_head指针去操作BufferCache。在操作系统中,VFS和VMM只与page_Cache交互,VMM负责 page_cache的分配与回收,同时在需要mmap时建立映射。VFS负责 应用层数据与 page_cache的交互。而buffer_cache只与具体的文件系统进行交互,具体的文件系统负责外设与BufferCache之间进行数据交互。
BufferCache 与文件与硬件关系
File中是文件的逻辑地址,所以相邻的文件地址真正存到磁盘的数据并不一定相邻。
page_cache 管理 buffer_cache
page_cache管理
page_cache通过俩个数据结构管理。一个是radix_tree 一个是双向链表。Radix_tree 是属于inode节点来管理的,它主要负责根据文件偏移量来快速索引到page_cache。双向链表则是主要负责page_cache的回收,在内核中主要维护了active_list 与 inactive_list 俩个链表来实现物理内存的回收,这也就是Linux中的页面置换算法。
下图是 radix tree的一个示意图,该 radix tree 的分叉为4(22),树高为4,用来快速定位8位文件内偏移。Linux(2.6.7) 内核中的分叉为 64(26),树高为 6(64位系统)或者 11(32位系统),用来快速定位 32 位或者 64 位偏移,radix tree 中的每一个叶子节点指向文件内相应偏移所对应的Cache项.
page_cache的预读与替换策略
Linux内核的文件预读算法主要根据Cache是否命中来决策。当一次读请求的时候,Linux会读入所请求的页面并读入紧随其后的少数几个页面(不少于一个页面,通常是三个页面),这个时候的读取为同步读取。接下来的策略就看Cache是否命中
- 如果命中,系统把预读group扩大一倍,并让底层具体的文件系统继续读取其后的block块到page_cache中,这个时候读取称为异步读取
- 如果没命中,则表示文件并非顺序访问,此次读取页面不在之前预读的group中,系统继续采用同步读取,读取正确的数据到group中。
如下a显示读前结果,b显示未命中结果,C显示命中结果
页面置换伪代码
Mark_Accessed(b) {
if b.state==(UNACTIVE && UNREFERENCE)
b.state = REFERENCE
else if b.state == (UNACTIVE && REFERENCE) {
b.state = (ACTIVE && UNREFERENCE)
Add X to tail of active_list
} else if b.state == (ACTIVE && UNREFERENCE)
b.state = (ACTIVE && REFERENCE)
}
Reclaim() {
if active_list not empty and scan_num<MAX_SCAN1
{
X = head of active_list
if (X.state & REFERENCE) == 0
Add X to tail of inactive_list
else
{
X.state &= ~REFERENCE Move X to tail of active_list
}
scan_num++
}
scan_num = 0
if inactive_list not emptry and scan_num < MAX_SCAN2
{
X = head of inactive_list
if (X.state & REFERENCE) == 0
return X
else
{
X.state = ACTIVE | UNREFERENCE
Move X to tail of active_list
}
scan_num++
}
return NULL
}
Access(b)
{
if b is not in cache {
if slot X free
put b into X
else {
X=Reclaim()
put b into X
}
Add X to tail of inactive_list
}
Mark_Accessed(X)
}
文件操作API与 page_cache关系
非mmap
这类API基本上是用于 应用层数据 与 page_cache的交互,或者page_cache之间的互相交互
mmap
第二种类型的API将page_cache项映射到用户空间,使得应用程序可以像使用内存指针一样访问文件,mmap 访问Cache的方式在内核中是采用请求页面机制实现的,其工作过程如下图所示。
- 应用程序调用mmap(图中1)
- 陷入到内核中后调用do_mmap_pgoff(图中2)
- 该函数从应用程序的地址空间中分配一段区域作为映射的内存地址,并使用一个VMA(vm_area_struct)结构代表该区域,之后就返回到应用程序(图中3)
- 当应用程序访问mmap所返回的地址指针时(图中4),由于虚实映射尚未建立,会触发缺页中断(图中5)。
- 系统会调用缺页中断处理函数(图中6),在缺页中断处理函数中,内核通过相应区域的VMA结构判断出该区域属于文件映射,于是调用具体文件系统的接口读入相应的Page Cache项(图中7、8、9),并填写相应的虚实映射表。
- 经过这些步骤之后,应用程序就可以正常访问相应的内存区域了。
Line 2
回头继续看Line2,used229468 表示应用程序真正使用到的内存大小。它的大小为 MemUsed - buffer - cached = 1149620 - 53744 - 866408 = 229468 。因为Linux 统计mem的时候包含了cache、buffer所以它的值显示出1149620而不是229468。但是如果即将有任何应用去想使用这些buffer/cache的空间,Linux将释放buffer/cache将其给应用使用。
3679332 是用Memtotal - Used = 3908800 - 229468 得到的,它表示用户还能使用多少内存空间。
\ | total | used | free | shared | buffers | cached |
---|---|---|---|---|---|---|
Mem | 3908800 | 1149620 | 2759180 | 0 | 53744 | 866408 |
-/+ buffers/cache | 229468 | 3679332 |
Line3
最后是swap区,它是由硬盘映射成虚拟内存,用来扩大虚拟内存容量,当访问swap区的内存时,发现其在硬盘上不在内存上会发生页面置换,把swap区的内容加载到内存,把内存的不用的页换回到硬盘上。
\ | total | used | free | shared | buffers | cached |
---|---|---|---|---|---|---|
Swap | 3145720 | 0 | 3145720 |
选项
free -k kb
free -m mb
free -g Gb
free --tera -Tb
free --si -g 以1000为单位显示大小默认1024
free -t 显示 swap和内存的综合
free -s 1 以 num秒数为间隔输出结果
watch free 加上watch可以更好的动态使用free命令