剖析top命令显示的VIRT RES SHR值

2023-11-10

http://yalung929.blog.163.com/blog/static/203898225201212981731971/
http://www.fuzhijie.me/?p=741

引 言: top命令作为Linux下最常用的性能分析工具之一,可以监控、收集进程的CPU、IO、内存使用情况。比如我们可以通过top命令获得一个进程使用了多少虚拟内存(VIRT)、物理内存(RES)、共享内存(SHR)。
  最近遇到一个咨询问题,某产品做性能分析需要获取进程占用物理内存的实际大小(不包括和其他进程共享的部分),看似很简单的问题,但经过研究分析后,发现背后有很多故事;

1 VIRT RES SHR的准确含义

三个内存指标,VRIT,RES,SHR准确含义是什么?谁能告诉我们?MAN页?Linux专家?SUSE工程师?Linus?谁能说出最正确答案?没人!因为惟有源代码才是最正确的答案。
  那我们就去看下源码吧,这就是开源软件的最大的好处。
  首先这三个数据的源头,肯定是内核,进程的相关数据结构肯定是由内核维护。那么top作为一个用户空间的程序,要想获取内核空间的数据,就需要通过系统接口(API)获取。而proc文件系统是Linux内核空间和用户空间交换数据的一个途径,而且是非常重要的一种途径,这点和windows更倾向于基于函数调用的形式不同。
  当你调用系统函数read读取一个普通文件时,内核执行对应文件系统的代码从磁盘传送文件内容给你。
  当你调用系统函数read读取一个 proc文件时,内核执行对应的proc文件系统的代码从内核的数据结构中传送相关内容给你。proc文件和磁盘没有关系。只是系统接口而已。
  而一个进程的相关信息,Linux全部通过/proc//内的文件告诉了我们。
  如下,你可以使用普通的文件读写工具,比如cat获取进程的各种信息。这比函数调用的方式灵活多了、丰富多了。

回到我们的问题,top命令显示的进程信息,肯定也是通过proc获取的,因为除此之外没有其他途径,没有系统函数可以做这个事情,top也不可能越过用户层直取内核获取数据。
  带着以上信息,很快就可以从top的源码中找到关键代码:

啊哈,statm文件:

根据sscanf的顺序,第一个值是VIRT,第二个值是RES,第三个值是SHR!
  等等,好像数值对不上,top显示的SHR是344k,而statm给出的是86!
  再来看一行关键代码:

statm显示的是页数,top显示的是KB。X86下,一页是4KB,86 * 4 = 344。这就对了!
  
  于是乎,我们找到了最关键的入口,接下来按图索骥,看看内核是怎么产生statm文件内容就可以了。~~

proc_pid_statm函数负责产生statm文件内容,当你使用cat命令打印statm文件时,内核中的这个函数会执行。
  proc_pid_statm获取进程的mm_struct数据结构,而这个数据结构就是进程的内存描述符,通过它可以获取进程内存使用、映射的全部信息。
       进一步考察task_statm函数,可以看到:

这个比较清晰,只要进程申请了内存,无论是malloc还是堆栈还是全局,都会计入这个值;
  第二个值(RES)是mm->file_rss+mm->anon_rss;
  第三个值(SHR)是mm->file_rss。
   RES要和SHR结合者看,内核把物理内存分为了两部分,一部分是映射至文件的,一部分是没有映射至文件的即匿名内存,完全和共不共享没有关系!
  但file_rss为什么叫做shared呢?应该是一种指示性表述,表示这部分内存可能是共享的。但并不代表真正共享了。那么到底哪些计入file_rss?通过查阅相关代码,发现(可能有遗漏):
  l 程序的代码段。
  l 动态库的代码段。
  l 通过mmap做的文件映射。
  l 通过mmap做的匿名映射,但指明了MAP_SHARED属性。
  l 通过shmget申请的共享内存。
   即进程通过以上方式占用的物理内存,计入file_rss,也就是top的SHR字段。我们看到一般这些内存都是以共享方式存在。但如果某个动态库只一个进程在使用,它的代码段就没有被共享着。
  反过来再来看anon_rss统计的内容,是否就一定是独占的?也不是,比如新fork之后的子进程,由于copy on write机制,在页面被修改之前,和父进程共享。这部分值并不体现在top命令的SHR字段内。
   综上所述top命令显示的SHR字段,并不是准确描述了进程与其他进程共享使用的内存数量,是存在误差的。
  那么如何获取进程准确的共享内存数量?
2 获取进程准确的共享内存数量
  我们注意到在描述进程信息的proc/内,有一个smaps文件,里面展示了所有内存段的信息,其中有Shared_Clean Shared_Dirty Private_Clean Private_Dirty:几个字段。

找到相关代码,可以看到,一个页面如果映射数>=2计入Shared_* ; 如果=1计入Private_*。(脏页计入*_Dirty,否则计入*_Clean)

统计smaps文件内所有段的Shared_*值的总和就是进程准确的共享内存数量!
       统计smaps文件内所有段的Private_*值的总和就是进程准确的独占内存数量!
3 总结
  通过以上分析,我们可以得到如下结论:
  l top命令通过解析/proc//statm统计VIRT和RES和SHR字段值。
  l VIRT是申请的虚拟内存总量。
  l RES是进程使用的物理内存总和。
  l SHR是RES中”映射至文件”的物理内存总和。包括:
  程序的代码段。
  动态库的代码段。
  通过mmap做的文件映射。
  通过mmap做的匿名映射,但指明了MAP_SHARED属性。
  通过shmget申请的共享内存。
  l /proc//smaps内Shared_*统计的是RES中映射数量>=2的物理内存。
  l /proc//smaps内Private_*统计的是RES中映射数量=1的物理内存。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

剖析top命令显示的VIRT RES SHR值 的相关文章

  • Tomcat Intellij Idea:远程部署

    RackSpace 云服务器 Ubuntu 12 04 Intellij Idea 11 1 2 Windows 8 Tomcat 7 0 26 JDK 6 在 Intellij Idea 上 当我尝试在远程 Tomcat 7 服务器上运行
  • ioctl 命令的用户权限检查

    我正在实现 char 驱动程序 Linux 并且我的驱动程序中有某些 IOCTL 命令仅需要由 ADMIN 执行 我的问题是如何在 ioctl 命令实现下检查用户权限并限制非特权用户访问 IOCTL 您可以使用bool capable in
  • 批量删除文件名中包含 BASH 中特殊字符的子字符串

    我的目录中有一个文件列表 opencv calib3d so2410 so opencv contrib so2410 so opencv core so2410 so opencv features2d so2410 so opencv
  • 找不到包“gdk-pixbuf-2.0”

    我正在尝试在 Amazon Linux 发行版实例上构建 librsvg 我已经通过 yum 安装了大部分依赖项 其中一些在实例上启用的默认 yum 存储库中不可用 因此必须从头开始构建它们 我已经走了很远 但还停留在最后一点 跑步时sud
  • 为什么 Linux 原始套接字的 RX 环大小限制为 4GB?

    背景 我试图mmap 我的原始套接字的 RX 环形缓冲区64 bitLinux 应用程序 我的环由 4096 个块组成 每个块大小为 1MB 总共 4GB 请注意 每个 1MB 块中可以有许多帧 如果您好奇 请参阅此文档了解背景信息 htt
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终
  • 适用于 Linux 的轻量级 IDE [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 .gitconfig 中隐藏 GitHub 令牌

    我想将所有点文件存储在 GitHub 上 包括 gitconfig 这需要我将 GitHub 令牌隐藏在 gitconfig 中 为此 我有一个 gitconfig hidden token 文件 这是我打算编辑并放在隐藏令牌的 git 下
  • 如何使用 Cloud Init 挂载未格式化的 EBS 卷

    Context 我正在使用https wiki jenkins io display JENKINS Amazon EC2 Plugin https wiki jenkins io display JENKINS Amazon EC2 Pl
  • linux-x64 二进制文件无法在 linuxmusl-x64 平台上使用错误

    我正在安装Sharp用于使用 package json 的 Nodejs 项目的 docker 映像上的映像压缩包 当我创建容器时 我收到有关 Sharp 包的以下错误 app node modules sharp lib libvips
  • 如何在 Ubuntu 中创建公共 HTML 文件夹?

    简单的问题 但由于某种原因我无法在谷歌上找到确切的答案 我在 Slicehost 上安装了全新的 Ubuntu 并且想在我的主目录中为包含一堆静态 HTML 文件的简单网站创建一个公共目录 我该怎么做呢 只是打字的问题吗mkdir publ
  • 如何阻止ubuntu在使用apt安装或更新软件包时弹出“Daemons using outdatedlibraries”? [关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 我最近新安装了 Ubuntu 22 04 LTS 我发现每次使用 apt 安装或更新软件包时 它都会询问我有关Which servic
  • GMail 421 4.7.0 稍后重试,关闭连接

    我试图找出为什么它无法使用 GMail 从我的服务器发送邮件 为此 我使用 SwiftMailer 但我可以将问题包含在以下独立代码中
  • 在 Mono 上运行 .Net MVC5 应用程序

    我正在 Windows 上的 Visual Studio 2013 中开发 Net 4 5 1 MVC5 应用程序 现在我想知道 是否可以在Linux Ubuntu 12 04 上运行这个应用程序 可以使用OWIN吗 Owin 可以自托管运
  • Bash - 在与当前终端分开的另一个终端中启动命令的新实例

    我有一个简单的 bash 脚本 test sh 设置如下 bin bash args if args 0 check capture then watch n 1 ls lag home user capture0 watch n 1 ls
  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 错误:“rjags”的包或命名空间加载失败

    在终端的 conda 环境之一中 我能够成功安装包 rjags 但是 当我在该环境中运行 R 并运行库 rjags 时 出现以下错误 加载所需的包 coda 错误 rjags 的包或命名空间加载失败 rjags 的 loadNamespac
  • 在生产服务器上使用 Subversion 使文件生效的最佳方法是什么?

    目前我已经设置了 subversion 这样当我在 Eclipse PDT 中进行更改时 我可以提交更改 它们将保存在 home administrator 中项目文件 该文件具有 subversion 推荐的 branches tags
  • Linux/POSIX:为什么 fork() 不分叉*所有*线程

    众所周知 POSIX下创建新进程的默认方式是使用fork 在 Linux 下 这在内部映射到clone 我想知道的是 众所周知 当一个人打电话时fork 子进程是用单个线程创建的 调用的线程fork cf https linux die n
  • 我什么时候应该编写 Linux 内核模块?

    有些人出于某种原因想要将 Linux 中的代码从用户空间移动到内核空间 很多时候 原因似乎是代码应该具有特别高的优先级 或者只是 内核空间更快 这对我来说似乎很奇怪 我什么时候应该考虑编写内核模块 有一套标准吗 我怎样才能激励将代码保存在

随机推荐

  • conda install R语言报错问题血泪解决

    今天在安装conda之后 想安装r语言环境 却遇到如下报错 真的超级郁闷 conda install r Collecting package metadata current repodata json failed CondaHTTPE
  • LeetCode 2488. 统计中位数为K的子数组

    题目描述 给你一个长度为 n 的数组 nums 该数组由从 1 到 n 的 不同 整数组成 另给你一个正整数 k 统计并返回 nums 中的 中位数 等于 k 的非空子数组的数目 注意 数组的中位数是按 递增 顺序排列后位于 中间 的那个元
  • sqli - labs -Less - 7 ~ 8

    输入id 1显示正常 输入id 1 报错 这里我们无法从错误信息中找到我们需要的东西 就要用到盲注了 lt 这里的盲注指的是布尔盲注 gt 所谓盲注就是我们去猜测数据库的长度等等 再结合语句去验证从而得到我们想要的信息 我们依然是用burp
  • 在HTML5中有什么可以替代iFrame

    最佳解决方法 通常有4种方法可以将HTML嵌入到网页中 iframe的内容完全位于当前页面不同的上下文中 虽然这是一个很棒的功能 而且是不同浏览器版本之间兼容最好的 但是它也带来了额外的问题 将frame大小跟网页内容设置一致比较麻烦 AJ
  • C语言代码覆盖率测试工具-OpenCppCoverage介绍

    代码覆盖率测试工具名称 OpenCppCoverage 简介 OpenCppCoverage是2014年推出的Windows平台下开源的C 代码覆盖率工具 类似于Linux下gcc内嵌的gcov工具 它不需要在编译时插桩 只需要有编译生成的
  • 17.进程同步与死锁——信号量临界区保护

    1 温故知新 通过对信号量的访问和修改 让进程有序推进 问题 empty值必须是正确的 如果empty错了 就不能有序推进了 2 共同修改信号量引出的问题 生产者 Producer item P empty 生产者先判断 缓存区个数 emp
  • 富文本图片怎么上传_django上传图片到七牛云-富文本编辑器上传图片到七牛云...

    django创建项目 默认是保存资源到本地的 但是由于会占用太多的存储空间 对日后管理和升级不太友善 所以一般会把静态资源保存在第三方存储库里 这里 我们就是用到了七牛云 云存储 安装七牛云所需要的包 pip install django
  • 教你在M1芯片的imac一体机上安装PS2021 附教程和方法适用于所有Mac

    提示 文章转载自互联网 文章目录 前言 一 正确安装流程 二 注意事项 总结 前言 苹果在21年4月发布了搭载M1芯片的一体机产品 imac 2021 惊艳的机生设计和超薄的厚度实在是太香了 关键是性价比还算不错 详细大部分购买Imac的用
  • 4. 定时器(TIM)(定时器计数)

    1 TIM简介 TIM Timer 定时器 定时器可以对输入的时钟进行计数 并在计数值达到设定值时触发中断 16位计数器 预分频器 自动重装寄存器的时基单元 在72MHz计数时钟下可以实现最大59 65s 1 72 2 16 2 16 2
  • 多服务器分布式系统架构,集中式架构与分布式架构,你了解多少?

    原标题 集中式架构与分布式架构 你了解多少 什么是集中式 集中式架构就是将项目集中存储在中央服务器中 在工作的时候 大家只要自己电脑上操作 从同一个地方下载最新版本 然后开始工作 做完的工作再提交给中央服务器保存 这种方式需要联网 典型的例
  • 翻译:Apache Linkis Graduated to Apache Top-Level Project(Apache Linkis 升级为顶级项目)

    Apache Linkis是一个计算中间件 作为上层应用和底层引擎之间的一层 如Apache Spark Apache Hive和Apache Flink 它在2021年作为一个Apache孵化器项目开始 并在2023年1月升级为顶级项目
  • Spring Boot

    前言 什么是Spring Boot 为什么要学Spring Boot Spring 的诞 是为了简化Java 程序的开发的 Spring Boot 的诞 是为了简化Spring 程序开发 的 Spring就像汽车 相比以前人只能其自行车走路
  • CGAL 使用Voronoi协方差估计点云的法线

    目录 一 算法原理 1 主要函数 二 代码实现 一 算法原理 1 主要函数 头文件 include
  • IO多路复用之select、poll、epoll

    五种网络I O模型 如果使用多进程 多线程模式的话 创建进程和创建线程需要时间开销 在编写服务器客户端程序时 如果服务器性能不行而客户端太多时这种代价很大 试想如果有一种方法能够同时监听按键设备 串口设备和网络socket的事件 可读 可写
  • 【Python零基础入门篇 · 11】:类型转换和深浅拷贝,可变对象和不可变对象、pass语句

    文章目录 int float str repr eval的类型转换 list str tuple三者的类型相互转换 深浅拷贝 浅拷贝 数据半共享 深拷贝 数据完全不共享 可变对象和不可变对象 可变对象 不可变对象 pass语句 int fl
  • HDMI和DP线的等级和速度

    转自 4K 144Hz到底需要多少带宽
  • Unity3D的GetComponent<>()

    GetComponent 是Unity游戏引擎中的一个函数 用于获取游戏对象上附加的组件 在Unity中 游戏对象可以添加各种不同的组件来实现不同的功能 比如 Transform组件用于控制游戏对象的位置 旋转和缩放 Renderer组件用
  • C++实验: 运算符重载

    C 实验 运算符重载 1 实验目的 1 进一步了解运算符重载的概念与使用方法 2 掌握几种常用的运算符重载方法 3 了解转换构造函数的使用方法 4 了解在Visual C 6 0环境下进行运算符重载要注意的问题 2 实验内容 1 声明一个复
  • NET Core 3.0 AutoFac替换内置DI的新姿势

    NET Core 3 0 和 以往版本不同 替换AutoFac服务的方式有了一定的变化 在尝试着升级项目的时候出现了一些问题 原来在NET Core 2 1时候 AutoFac返回一个 IServiceProvider 参数注入到Confi
  • 剖析top命令显示的VIRT RES SHR值

    http yalung929 blog 163 com blog static 203898225201212981731971 http www fuzhijie me p 741 引 言 top命令作为Linux下最常用的性能分析工具之