【转载】【内存】procmeminfo之谜完全揭秘

news/2024/11/14 12:40:40/文章来源:https://www.cnblogs.com/dongxb/p/18301508

本文转发自:http://linuxperf.com/?p=142

应该是迄今为止对/proc/meminfo描述最全面与完整的一篇文章。

free 命令是Linux系统上查看内存使用状况最常用的工具,然而很少有人能说清楚 “buffers” 与 “cached” 之间的区别:

我们先抛出结论,如果你对研究过程感兴趣可以继续阅读后面的段落:

buffers 表示块设备(block device)所占用的缓存页,包括:直接读写块设备、以及文件系统元数据(metadata),比如SuperBlock所使用的缓存页;

cached 表示普通文件数据所占用的缓存页。

下面是分析过程:

先用 strace 跟踪 free 命令,看看它是如何计算 bufferscached 的:

# strace free
...
open("/proc/meminfo", O_RDONLY)         = 3
lseek(3, 0, SEEK_SET)                   = 0
read(3, "MemTotal:        3848656 kB\nMemF"..., 2047) = 1170
...

显然 free 命令是从 /proc/meminfo 中读取信息的,跟我们直接读到的结果一样:

# cat /proc/meminfo
MemTotal:        3848656 kB
MemFree:          865640 kB
Buffers:          324432 kB
Cached:          2024904 kB
...
SwapTotal:       2031612 kB
SwapFree:        2031612 kB
...
Shmem:              5312 kB
...

那么 /proc/meminfo 中的 BuffersCached 又是如何得来的呢?这回没法偷懒,只能去看源代码了。源代码文件是:fs/proc/meminfo.c ,我们感兴趣的函数是:meminfo_proc_show(),阅读得知:

Cached 来自于以下公式:

global_page_state(NR_FILE_PAGES) – total_swapcache_pages – i.bufferram

global_page_state(NR_FILE_PAGES) 表示所有的缓存页(page cache)的总和,它包括:

  • Cached
  • Buffers 也就是上面公式中的 i.bufferram,来自于 nr_blockdev_pages() 函数的返回值。
  • 交换区缓存(swap cache)

global_page_state(NR_FILE_PAGES) 来自 vmstat[NR_FILE_PAGES]vmstat[NR_FILE_PAGES] 可以通过 /proc/vmstat 来查看,表示所有缓存页的总数量:

# cat /proc/vmstat
...
nr_file_pages 587334
...

注意以上nr_file_pages是以page为单位(一个page等于4KB),而free命令是以KB为单位的。

直接修改 nr_file_pages 的内核函数是:
__inc_zone_page_state(page, NR_FILE_PAGES)__dec_zone_page_state(page, NR_FILE_PAGES),一个用于增加,一个用于减少。

Swap Cache是什么?

用户进程的内存页分为两种:file-backed pages(与文件对应的内存页)和anonymous pages(匿名页)。匿名页(anonymous pages)是没有关联任何文件的,比如用户进程通过malloc()申请的内存页,如果发生swapping换页,它们没有关联的文件进行回写,所以只能写入到交换区里。

交换区可以包括一个或多个交换区设备(裸盘、逻辑卷、文件都可以充当交换区设备),每一个交换区设备在内存里都有对应的swap cache,可以把swap cache理解为交换区设备的page cachepage cache对应的是一个个文件,swap cache对应的是一个个交换区设备,kernel管理swap cache与管理page cache一样,用的都是radix-tree,唯一的区别是:page cache与文件的对应关系在打开文件时就确定了,而一个匿名页只有在即将被swap-out的时候才决定它会被放到哪一个交换区设备,即匿名页与swap cache的对应关系在即将被swap-out时才确立。

并不是每一个匿名页都在swap cache中,只有以下情形之一的匿名页才在:

  • 匿名页即将被swap-out时会先被放进swap cache,但通常只存在很短暂的时间,因为紧接着在pageout完成之后它就会从swap cache中删除,毕竟swap-out的目的就是为了腾出空闲内存;
    【注:参见mm/vmscan.c: shrink_page_list(),它调用的add_to_swap()会把swap cache页面标记成dirty,然后它调用try_to_unmap()将页面对应的page table mapping都删除,再调用pageout()回写dirty page,最后try_to_free_swap()会把该页从swap cache中删除。】
  • 曾经被swap-out现在又被swap-in的匿名页会在swap cache中,直到页面中的内容发生变化、或者原来用过的交换区空间被回收为止。
    【注:当匿名页的内容发生变化时会删除对应的swap cache,代码参见mm/swapfile.c: reuse_swap_page()。】

cached:

Cached 表示除去 buffersswap cache 之外,剩下的也就是普通文件的缓存页的数量:

global_page_state(NR_FILE_PAGES) – total_swapcache_pages – i.bufferram

所以关键还是要理解 buffers 是什么含义。

buffers:

从源代码中看到,buffers 来自于 nr_blockdev_pages() 函数的返回值:

long nr_blockdev_pages(void)
{struct block_device *bdev;long ret = 0;spin_lock(&bdev_lock);list_for_each_entry(bdev, &all_bdevs, bd_list) {ret += bdev->bd_inode->i_mapping->nrpages;}spin_unlock(&bdev_lock);return ret;
}

这段代码的意思是遍历所有的块设备(block device),累加每个块设备的inodei_mapping的页数,统计得到的就是 buffers。显然 buffers 是与块设备直接相关的。

那么谁会更新块设备的缓存页数量(nrpages)呢?我们继续向下看。

搜索kernel源代码发现,最终点我更新mapping->nrpages字段的函数就是:

pagemap.h: add_to_page_cache
> filemap.c: add_to_page_cache_locked
C__add_to_page_cache_locked
> page_cache_tree_insert
和:
filemap.c: delete_from_page_cache
> __delete_from_page_cache
> page_cache_tree_delete
static inline int add_to_page_cache(struct page *page,struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask)
{int error;__set_page_locked(page);error = add_to_page_cache_locked(page, mapping, offset, gfp_mask);if (unlikely(error))__clear_page_locked(page);return error;
}void delete_from_page_cache(struct page *page)
{struct address_space *mapping = page->mapping;void (*freepage)(struct page *);BUG_ON(!PageLocked(page));freepage = mapping->a_ops->freepage;spin_lock_irq(&mapping->tree_lock);__delete_from_page_cache(page, NULL);spin_unlock_irq(&mapping->tree_lock);mem_cgroup_uncharge_cache_page(page);if (freepage)freepage(page);page_cache_release(page);
}

这两个函数是通用的,block device 和 文件inode 都可以调用,至于更新的是块设备的(buffers)还是文件的(cached),取决于参数变量mapping如果mapping对应的是块设备,那么相应的统计信息会反映在 buffers 中;如果mapping对应的是文件inode,影响的就是 cached。我们下面看看kernel中哪些地方会把块设备的mapping传递进来。

首先是块设备本身,打开时使用 bdev->bd_inode->i_mapping

static int blkdev_open(struct inode * inode, struct file * filp)
{struct block_device *bdev;/** Preserve backwards compatibility and allow large file access* even if userspace doesn't ask for it explicitly. Some mkfs* binary needs it. We might want to drop this workaround* during an unstable branch.*/filp->f_flags |= O_LARGEFILE;if (filp->f_flags & O_NDELAY)filp->f_mode |= FMODE_NDELAY;if (filp->f_flags & O_EXCL)filp->f_mode |= FMODE_EXCL;if ((filp->f_flags & O_ACCMODE) == 3)filp->f_mode |= FMODE_WRITE_IOCTL;bdev = bd_acquire(inode);if (bdev == NULL)return -ENOMEM;filp->f_mapping = bdev->bd_inode->i_mapping;return blkdev_get(bdev, filp->f_mode, filp);
}

其次,文件系统的Superblock也是使用块设备:

struct super_block {...struct block_device     *s_bdev;...
}int inode_init_always(struct super_block *sb, struct inode *inode)
{
...if (sb->s_bdev) {struct backing_dev_info *bdi;bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;mapping->backing_dev_info = bdi;}
...
}

sb表示SuperBlocks_bdev就是块设备。Superblock是文件系统的metadata(元数据),不属于文件,没有对应的inode,所以,对metadata操作所涉及的缓存页都只能利用块设备mapping,算入 buffers 的统计值内。

如果文件含有间接块(indirect blocks),因为间接块也属于metadata,所以走的也是块设备的mapping。查看源代码,果然如此:

ext4_get_blocks
->  ext4_ind_get_blocks->  ext4_get_branch->  sb_getblkstatic inline struct buffer_head *
sb_getblk(struct super_block *sb, sector_t block)
{                       return __getblk(sb->s_bdev, block, sb->s_blocksize);
}

这样我们就知道了buffers 是块设备(block device)占用的缓存页,分为两种情况:

  • 直接对块设备进行读写操作;
  • 文件系统的metadata(元数据),比如 SuperBlock

验证:

现在我们来做个测试,验证一下上述结论。既然文件系统的metadata会用到 buffers,我们用 find 命令扫描文件系统,观察 buffers 增加的情况:

# freetotal       used       free     shared    buffers     cached
Mem:       3848656    2889508     959148       5316     263896    2023340
-/+ buffers/cache:     602272    3246384
Swap:      2031612          0    2031612# find / -name abc.def# freetotal       used       free     shared    buffers     cached
Mem:       3848656    2984052     864604       5320     319612    2023348
-/+ buffers/cache:     641092    3207564
Swap:      2031612          0    2031612

再测试一下直接读取block device,观察buffers增加的现象:

# freetotal       used       free     shared    buffers     cached
Mem:       3848656    3006944     841712       5316     331020    2028648
-/+ buffers/cache:     647276    3201380
Swap:      2031612          0    2031612# dd if=/dev/sda1 of=/dev/null count=2000
2000+0 records in
2000+0 records out
1024000 bytes (1.0 MB) copied, 0.026413 s, 38.8 MB/s# freetotal       used       free     shared    buffers     cached
Mem:       3848656    3007704     840952       5316     331872    2028692
-/+ buffers/cache:     647140    3201516
Swap:      2031612          0    2031612

结论:

free 命令所显示的 buffers 表示块设备(block device)所占用的缓存页,包括直接读写块设备、以及文件系统元数据(metadata)如SuperBlock所使用的缓存页;而 cached 表示普通文件所占用的缓存页。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/743535.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PMP-项目运行环境

影响项目环境有两大客观因素和人,两大客观因素:事业环境因素和组织过程资产。 事业环境因素 包括组织外部因素和组织内部因素,组织内部因素是组织可以改变的,但是项目不能我改变;在默认条件下事业环境因素是项目无法改变的。 事业环境因素是指项目团队不能控制的,将对项目…

易优cms伪静态后动态URL百度收录的内容404

伪静态后,动态URL百度已经收录过的内容404。怎么解?如果伪静态 动态打不开 你想不出现404 最简单的办法就是改为动态本文来自博客园,作者:黄文Rex,转载请注明原文链接:https://www.cnblogs.com/hwrex/p/18301468

User red has exceeded the max_updates resource (current value: 500)

错误记录: User red has exceeded the max_updates resource (current value: 500) 错误原因: 在mysql数据库的下有一个库为mysql,它其中有一个表为user这里面的纪录每一条都对应为一个mysql用户的授权。其中字段 max_questions max_updates max_connections分别记录着最大查…

11、Oracle中的视图

最近项目要用到Oracle,奈何之前没有使用过,所以在B站上面找了一个学习视频,用于记录学习过程以及自己的思考。 视频链接: 【尚硅谷】Oracle数据库全套教程,oracle从安装到实战应用 如果有侵权,请联系删除,谢谢。学习目标:描述视图 创建和修改视图的定义,删除视图 从视…

廉价平替esphome水浸 雨水传感器diy

esp8266 nodemcu + 雨水传感器 diy厨房水浸传感器 首先在esphome中添加设备esp8266 nodemcu + 雨水传感器 diy厨房水浸传感器esphome 配置编写 # 8266平台配置 esp8266:board: nodemcuv2 # 水浸 雨水 传感器 binary_sensor:- platform: gpiopin:number: GPIO2inverted: truenam…

关于win显示器开启HDR后B站截图出现过曝情况的临时解决方法

在显示器开启HDR后,最近发现截图B站时会出现图片过曝光,只有视频截图异常,其他截图页面正常,如下按照网上的教程 解决windows显示开启HDR后chrome内截图泛白问题 设置了chrome 浏览器的色彩,但是还是无法解决,怀疑是视频播放器的原因,目前只能通过如下方法暂时规避:在网…

时序数据从通用数据库切换到influxdb后,在查询、分析方面能获取哪些便利?

数据抽稀 如传感器5s上报一次数据,某些场景下,为了性能考虑,需要20s或者5min返回一个point select last(mileage) from device_data_old where deviceId= 00130846142 and time> now() -60m group by time(5m);注意: 03:40 取的是03:44:55时间点的值。即time返回的是滚动…

Simplifying Content-Based Neural News Recommendation: On User Modeling and Training Objectives论文阅读笔记

Simplifying Content-Based Neural News Recommendation: On User Modeling and Training Objectives论文阅读笔记 Abstract 存在的问题: ​ (1) 尽管设计具有普遍的同质性,但不同的评估数据集和协议阻碍了模型之间的直接比较;(2) 它使其他模型设计和训练目标的探索工作受到…

10、Oracle中的约 束constraint

最近项目要用到Oracle,奈何之前没有使用过,所以在B站上面找了一个学习视频,用于记录学习过程以及自己的思考。 视频链接: 【尚硅谷】Oracle数据库全套教程,oracle从安装到实战应用 如果有侵权,请联系删除,谢谢。学习目标:描述约束创建和维护约束1、什么是约束 约束是表…

nacos 服务注册原理

springboot 的各种 starter 会根据 SPI 机制,读取 META-INFO/spring.factories 文件,自动注册一些 bean,spring-cloud-starter-alibaba-nacos-discovery 的 spring.factories 如下: org.springframework.cloud.bootstrap.BootstrapConfiguration=\com.alibaba.cloud.nacos.…