这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令;查看/proc/[pid]/下的文件。文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/下的文件内容进行了一些详细的介绍。文章内容来自google和自我总结,如有不当之处,欢迎批评指正。

查看Linux内存的方法

linux 下面查看内存有多种渠道,比如通过命令 ps ,top,free, pmap 等,或者通过/proc系统。一般情况下,ps,top,pmap,free可以满足要求,如果需要比较详细和精确地知道整机内存或者某个进程内存的使用情况,可以通过/proc 系统。

使用命令

free : 显示系统可用内存以及已经使用的内存的信息

ps: 查看进程信息,静态,即当前状态

top: 查看进程信息,动态

pstree: 查看进程树

pmap: 根据进程ID查看进程信息

ps vs top

  1. ps命令–提供系统过去信息的一次性快照,也就是说ps命令能够查看刚刚系统的进程信息。
  2. top命令反应的是系统进程动态信息,默认10s更新一次。
  3. ps和top都是从/proc目录下读取进程的状态信息,内核把当前系统进程的各种有用信息都放在这个伪目录下。

常见ps命令:

ps -aux: 查看系统所有进程

ps -l: 进查看自己的bash相关进程

top 命令详解,请参考http://www.jb51.net/article/40807.htm

基本命令:

  • 按键盘数字“1”,可监控每个逻辑CPU的状况:
  • 键盘“b”(打开/关闭加亮效果)
  • 键盘“x”(打开/关闭排序列的加亮效果)
  • ”shift + >”或”shift + <”可以向右或左改变排序列
  • 敲击“f”键,编排基本视图中的显示字段
  • s,改变画面更新频率
  • l,关闭或开启第一部分第一行 top 信息的表示
  • t,关闭或开启第一部分第二行 Tasks 和第三行 Cpus 信息的表示
  • m,关闭或开启第一部分第四行 Mem 和 第五行 Swap 信息的表示

具体使用方法,可以使用 man [cmd] 查看。

相关参数说明

VSZ & VIRT

  1. 进程使用的虚拟内存值总量,包括所有代码,数据,共享库已经被swapped out的。VIRT = SWAP + RES。
  2. VSZ来自ps命令, VIRT来自top命令,二者均表示进程占用的虚拟内存大小。
  3. 假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量

RES & RSS

  1. 进程当前使用的内存大小,但不包括swap out. RES = CODE +DATA。
  2. 包含其他进程的共享
  3. RES 来自 top 命令, RSS 来自 ps 命令,两者在表示意义上没有区别,都是从 /cat/proc/[pid]/stat 文件中读取的信息。
  4. 如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反
  5. 关于库占用内存的情况,它只统计加载的库文件所占内存大小

CODE

可执行代码占用的物理内存大小

DATA

  1. 物理内存中存放数据的大小,在程序运行中需要用到
  2. 如果top命令没有显示, 按f键显示

SHR

  1. 共享内存大小
  2. 除了自身进程的共享内存,也包含其他进程的共享内存
  3. 计算某个进程所占用物理内存的大小: RES - SHR
  4. swap out后,该值会下降。

查看一个进程的内存信息步骤

1.获取进程PID

$ ps -aux | grep /usr/sbin/NetworkManager
root 845 0.0 0.0 387084 13332 ? Ssl 3月28 0:00 /usr/sbin/NetworkManager --no-daemon

2.查看进程的所有线程

$ ps mp 845 -o THREAD,tid
USER %CPU PRI SCNT WCHAN USER SYSTEM TID
root 0.0 - - - - - -
root 0.0 19 - - - - 845
root 0.0 19 - - - - 1025
root 0.0 19 - - - - 1027

3.查看所有子进程

$ pstree -p 845
NetworkManager(845)─┬─dhclient(30278)
├─dnsmasq(1123)
├─{gdbus}(1027)
└─{gmain}(1025)

使用 /proc 下文件

/proc/[pid]/ 下面与进程内存相关的文件主要有maps , smaps, status。

maps: 文件可以查看某个进程的代码段、栈区、堆区、动态库、内核区对应的虚拟地址

smaps: 显示每个分区更详细的内存占用数据

status: 包含了所有CPU活跃的信息,该文件中的所有值都是从系统启动开始累计到当前时刻

有名与匿名:

一个文件可以映射到进程的一段内存区域中,映射的文件描述符保存在vm_area_struct->vm_file域中,这种内存区域叫做有名内存区域,相反,属于匿名映射内存区域。

maps 文件分析

Proc/[pid]/maps 显示进程映射了的内存区域和访问权限。对应内核中的操作集为 proc_pid_maps_op,具体的导出函数为 show_map 。内核中进程的一段地址空间用一个vm_area_struct结构体表示,所有地址空间存储在task->mm->mmap链表中。

截取一行内容如下:

7f4e3f5ca000-7f4e3f674000 r-xp 00000000 08:02 525202 /usr/lib/x86_64-linux-gnu/NetworkManager/libnm-device-plugin-wifi.so

Vm_area_struct每项对应解析如下表所示:

maps文件只能显示简单的分区,smap文件可以显示每个分区的更详细的内存占用数据。

smap 文件分析

截取一段文件,各字段解析如下:

7f148b2fa000-7f148b2fb000 rw-p 00026000 08:02 2883675 /lib/x86_64-linux-gnu/ld-2.23.so
Size: 4 kB 虚拟内存大小
Rss: 4 kB 实际使用物理内存大小 RSS = Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty
Pss: 4 kB RSS中私有的内存页面
Shared_Clean: 0 kB RSS中共享内存,没有被改写的页面
Shared_Dirty: 0 kB RSS中共享内存,被改写的页面
Private_Clean: 0 kB RSS中私有内存,未被改写
Private_Dirty: 4 kB RSS中私有内存,被改写
Referenced: 4 kB
Anonymous: 4 kB
AnonHugePages: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB 处于交换区的页面大小
SwapPss: 0 kB
KernelPageSize: 4 kB 操作系统一个页面大小
MMUPageSize: 4 kB 体系结构MMU一个页面大小
Locked: 0 kB
VmFlags: rd wr mr mw me dw ac sd

Dirty页面如果没有交换机制的情况下,应该是不能回收的。

分析脚本:

自己写了个简单的分析脚本,如下,可以根据需要进行修改。

#! /bin/bash
awk 'BEGIN{
total = 0;
printf("SIZE\tRSS\tSHARED_CLEAN\tSHARED_DIRTY\tPRIVATE_CLEAN\tPRIVATE_DIRTY\n")
}{
if(NF >3){
if($2 ~ /[r-][w-][x-][ps]/){
if($6 =="")
name = $1;
else
name = $6;
}
}
while(getline)
{
if(NF >3){
if($2 ~ /[r-][w-][x-][ps]/){
if($6 =="")
name = $1;
else
name = $6;
}
}
if($1 ~ /^Size/){
size = $2;
total += $2;
} if($1 ~ /Rss/){
rss = $2;
} if($1 ~ /Shared_Clean/){
shared_clean = $2;
}
if($1 ~ /Shared_Dirty/){
shared_dirty = $2;
} if($1 ~ /Private_Clean/){
private_clean = $2;
} if($1 ~ /Private_Dirty/){
private_dirty = $2;
}
if($1 ~ /VmFlags/){
printf("%d\t%d\t%d\t%d\t%d\t%d\t%s\n",size,rss,shared_clean,shared_dirty,private_clean,private_dirty,name);
size = 0;
name = "";
rss = 0;
shared_clean = 0;
shared_dirty = 0;
private_clean = 0;
private_dirty = 0;
continue;
}
}
}END{
printf("====total: %d\n", total);
}' $1

关于匿名映射

smaps 中可能会存在大量的匿名区域,它们是使用 mmap 机制生成的,但是没有关联到任何一个文件。通常情况下,它们主要用于处理一些琐碎的任务,比如处理没有在堆中申请的共享内存或者缓冲区。比如 pthread 使用匿名映射区作为新线程的栈,在linux 下,pthread 为 新线程申请 8M 空间作为栈空间 已经一个小小片内存(如4Kb)用于检测内存溢出。所以在每个pthread创建时,会分配一个映射到节点0的8Mb内存,和一个映射到节点0的4Kb区域。

status 文件分析

截取文件,解析个字段如下:

Develop>cat /proc/24475/status
Name: netio 可执行程序的名字
State: R (running) 任务状态,运行/睡眠/僵死
Tgid: 24475 线程组号
Pid: 24475 进程id
PPid: 19635 父进程id
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256 该进程最大文件描述符个数
Groups: 0
VmPeak: 6330708 kB 内存使用峰值
VmSize: 268876 kB 进程虚拟地址空间大小
VmLck: 0 kB 进程锁住的物理内存大小,锁住的物理内存无法交换到硬盘
VmHWM: 16656 kB
VmRSS: 11420 kB 进程正在使用的物理内存大小
VmData: 230844 kB 进程数据段大小
VmStk: 136 kB 进程用户态栈大小
VmExe: 760 kB 进程代码段大小
VmLib: 7772 kB 进程使用的库映射到虚拟内存空间的大小
VmPTE: 120 kB 进程页表大小
VmSwap: 0 kB
Threads: 5 共享使用该信号描述符的任务的个数,在POSIX多线程序应用程序中,线程组中的所有线程使用同一个信号描述符。
SigQ: 0/63346 待处理信号的个数
SigPnd: 0000000000000000 屏蔽位,存储了该线程的待处理信号
ShdPnd: 0000000000000000 屏蔽位,存储了该线程组的待处理信号
SigBlk: 0000000000000000 存放被阻塞的信号
SigIgn: 0000000001000000 存放被忽略的信号
SigCgt: 0000000180000000 存放被俘获到的信号
CapInh: 0000000000000000 能被当前进程执行的程序的继承的能力
CapPrm: ffffffffffffffff 进程能够使用的能力,可以包含CapEff中没有的能力,这些能力是被进程自己临时放弃的,CapEff是CapPrm的一个子集,进程放弃没有必要的能力有利于提高安全性
CapEff: ffffffffffffffff 进程的有效能力
CapBnd: ffffffffffffffff
Cpus_allowed: 01
Cpus_allowed_list: 0
Mems_allowed: 01
Mems_allowed_list: 0
voluntary_ctxt_switches: 201
nonvoluntary_ctxt_switches: 909

meminfo 文件分析

整机内存使用情况的文件/proc/meminfo,摘取分析如下

Develop>cat /proc/meminfo
MemTotal: 8112280 kB 所有可用RAM大小 (即物理内存减去一些预留位和内核的二进制代码大小)
MemFree: 4188636 kB LowFree与HighFree的总和,被系统留着未使用的内存
Buffers: 34728 kB 用来给文件做缓冲大小
Cached: 289740 kB 被高速缓冲存储器(cache memory)用的内存的大小
(等于 diskcache minus SwapCache )
SwapCached: 0 kB 被高速缓冲存储器(cache memory)用的交换空间的大小
已经被交换出来的内存,但仍然被存放在swapfile中。
用来在需要的时候很快的被替换而不需要再次打开I/O端口
Active: 435240 kB 在活跃使用中的缓冲或高速缓冲存储器页面文件的大小,
除非非常必要否则不会被移作他用
Inactive: 231512 kB 在不经常使用中的缓冲或高速缓冲存储器页面文件的大小,可能被用于其他途径.
Active(anon): 361252 kB
Inactive(anon): 120688 kB
Active(file): 73988 kB
Inactive(file): 110824 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB 交换空间的总大小
SwapFree: 0 kB 未被使用交换空间的大小
Dirty: 0 kB 等待被写回到磁盘的内存大小
Writeback: 0 kB 正在被写回到磁盘的内存大小
AnonPages: 348408 kB 未映射页的内存大小
Mapped: 33600 kB 已经被设备和文件等映射的大小
Shmem: 133536 kB
Slab: 55984 kB 内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗
SReclaimable: 25028 kB 可收回Slab的大小
SUnreclaim: 30956 kB 不可收回Slab的大小(SUnreclaim+SReclaimable=Slab)
KernelStack: 1896 kB 内核栈区大小
PageTables: 8156 kB 管理内存分页页面的索引表的大小
NFS_Unstable: 0 kB 不稳定页表的大小
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2483276 kB
Committed_AS: 1804104 kB
VmallocTotal: 34359738367 kB 可以vmalloc虚拟内存大小
VmallocUsed: 565680 kB 已经被使用的虚拟内存大小
VmallocChunk: 34359162876 kB
HardwareCorrupted: 0 kB
HugePages_Total: 1536 大页面数目
HugePages_Free: 0 空闲大页面数目
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB 大页面一页大小
DirectMap4k: 10240 kB
DirectMap2M: 8302592 kB

总结

linux下内存占用是一个比较复杂的概念,不能简单通过一个单一指标就判断某个程序“内存消耗”大小,因为进程所申请的内存不一定真正会被用到(malloc或mmap的实现)而且真正用到了的内存也不一定是只有该进程自己在用 (比如动态共享库)。我们应该根据具体需求选择合适的方式去分析内存占用。

性能分析 | Linux 内存占用分析的更多相关文章

  1. linux内存占用分析

    概述 想必在linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过top命令查看进程占用了多少内存.这里我们可以 ...

  2. Linux内存技术分析(上)

    Linux内存技术分析(上) 一.Linux存储器 限于存储介质的存取速率和成本,现代计算机的存储结构呈现为金字塔型.越往塔顶,存取效率越高.但成本也越高,所以容量也就越小.得益于程序访问的局部性原理 ...

  3. Linux内存技术分析(下)

    Linux内存技术分析(下) 五.内存使用场景 out of memory 的时代过去了吗?no,内存再充足也不可任性使用. 1.内存的使用场景 page 管理 slab(kmalloc.内存池) 用 ...

  4. Unity3D–Texture图片空间和内存占用分析(转载)

    原地址:http://www.unity蛮牛.com/home.php?mod=space&uid=1801&do=blog&id=756 Texture图片空间和内存占用分析 ...

  5. Unity3D–Texture图片空间和内存占用分析

    Texture图片空间和内存占用分析.由于U3D并没有很好的诠释对于图片的处理方式,所以很多人一直对于图集的大小和内存的占用情况都不了解.在此对于U3D的图片问题做一个实际数据的分析.此前的项目都会存 ...

  6. Linux 内存 占用较高问题排查

    Linux 内存 占用较高问题排查 niuhao307523005 2019-04-24 14:31:55 11087 收藏 11展开一 查看内存情况#按 k 查看 free #按兆M查看 free ...

  7. linux内存负载分析

    衡量内存负载的一个很重要的指标就是页面置换的频率.当linux系统频繁的对页进行换进换出 的时候,说明物理内存不过,不得不进行频繁的置换页面. 使用vmstat(virtual memory stat ...

  8. Windbg分析高内存占用问题

    1. 问题简介 最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声.为了缓解现场的情况, 客户都是手动回收IIS应用程序池才 ...

  9. PHP查询MySQL大量数据的内存占用分析

    这篇文章主要是从原理, 手册和源码分析在PHP中查询MySQL返回大量结果时, 内存占用的问题, 同时对使用MySQL C API也有涉及. 昨天, 有同事在PHP讨论群里提到, 他做的一个项目由于M ...

随机推荐

  1. weblogic 反序列化漏洞 getshell

    上传cmd.jsp,效果: 上传马:

  2. go语言入门(7)面向对象编程

    1,概述     对于面向对象编程的支持Go 语言设计得非常简洁而优雅.因为, Go语言并没有沿袭传统面向对象编程中的诸多概念,比如继承(不支持继承,尽管匿名字段的内存布局和行为类似继承,但它并不是继 ...

  3. C#验证控件使用方法及常用正则表达式例析(转)

    ASP.NET为开发人员提供了一整套完整的服务器控件来验证用户输入的信息是否有效.这些控件如下: 1.RequiredFieldValidator:验证一个必填字段,如果这个字段没填,那么,将不能提交 ...

  4. Java 读取 .properties 文件的几种方式

    Java 读取 .properties 配置文件的几种方式   Java 开发中,需要将一些易变的配置参数放置再 XML 配置文件或者 properties 配置文件中.然而 XML 配置文件需要通过 ...

  5. Navicat连接腾讯云实例MySQL

    Navicat连接腾讯云实例MySQL 授权所有的用户通过root账户 root密码登陆远程数据库 连接腾讯云实例上的MySQL数据库 这里的密码填入数据库的密码 这里的密码填入登陆云实例的密码也就是 ...

  6. 不创建父窗体的情况下他其他窗体的信息显示在第一个打开的窗体!(winfrom)

    公司使用vs2008做的东西,用vs2017都打不开了(编译错误) 叫我更新一下,我看了一下,08的项目 和 winform 差不多  如何就用winfrom来做了 (winform  很久没碰了,, ...

  7. Python&Selenium 关键字驱动测试框架之数据文件解析

    摘要:在关键字驱动测试框架中,除了PO模式以及一些常规Action的封装外,一个很重要的内容就是读写EXCEL,在团队中如何让不会写代码的人也可以进行自动化测试? 我们可以将自动化测试用例按一定的规格 ...

  8. Oracle 单列去重 显示单行所有列数据

    问题:test_table 表中有 a,b,c 三个字段,求根据字段a 去除重复数据,得到去重后的整行数据 根据mysql的经验尝试以下方法均失败 1.使用 distinct 关键字 (oracle查 ...

  9. [转载]Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  10. CSP-S2019 退役记/赛后总结

    真就退役了呗. 作为一名非常失败的OIer,开了一个非常失败的blog,一直想在赛后写点什么,做点什么,总结些什么.自csp结束以来,徘徊了半个月,今夜里终于还是起笔了. 因为从来没写过这种玩意,不妨 ...