精华内容
下载资源
问答
  • 这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令;查看/proc/[pid]/下的文件。文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/下的文件内容进行了一些详细的介绍。文章...

    这篇博客主要介绍 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/NetworkManagerroot 845 0.0 0.0 387084 13332 ? Ssl 3月28 0:00 /usr/sbin/NetworkManager --no-daemon

    2.查看进程的所有线程

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

    3.查看所有子进程

    $ pstree -p 845NetworkManager(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每项对应解析如下表所示:

    a8815d8641a9146b0562825e6220a33f.png

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

    smap 文件分析

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

    7f148b2fa000-7f148b2fb000 rw-p 00026000 08:02 2883675 /lib/x86_64-linux-gnu/ld-2.23.soSize: 4 kB 虚拟内存大小Rss: 4 kB 实际使用物理内存大小 RSS = Shared_Clean+Shared_Dirty+Private_Clean+Private_DirtyPss: 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 kBAnonymous: 4 kBAnonHugePages: 0 kBShared_Hugetlb: 0 kBPrivate_Hugetlb: 0 kBSwap: 0 kB 处于交换区的页面大小SwapPss: 0 kBKernelPageSize: 4 kB 操作系统一个页面大小MMUPageSize: 4 kB 体系结构MMU一个页面大小Locked: 0 kBVmFlags: rd wr mr mw me dw ac sd

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

    分析脚本:

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

    #! /bin/bashawk 'BEGIN{ total = 0; printf("SIZERSSSHARED_CLEANSHARED_DIRTYPRIVATE_CLEANPRIVATE_DIRTY") }{ 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%d%d%d%d%d%s
    展开全文
  • linux 内存占用过大分析

    万次阅读 2017-03-03 14:42:17
    1、使用 free -g 查看内存使用情况: 2、查看进程占用内存情况: ps aux|awk '{sum+=$6} END {print sum/...slab是Linux操作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,如进程描述符等

    1、使用 free -g 查看内存使用情况:


    2、查看进程占用的内存情况:

    ps aux|awk '{sum+=$6} END {print sum/1024}'

    结果发现占用了 17G


    3、查看内存分配情况:
    cat /proc/meminfo

    那slab是什么呢?

    slab是Linux操作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内碎片,而且处理速度也太慢。而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免这些内碎片。slab分配器并不丢弃已分配的对象,而是释放并把它们保存在内存中。当以后又要请求新的对象时,就可以从内存直接获取而不用重复初始化。

    具体为:

    采用伙伴算法分配内存时,每次至少分配一个页面。但当请求分配的内存大小为几十个字节或几百个字节时应该如何处理?如何在一个页面中分配小的内存区,小内存区的分配所产生的内碎片又如何解决?

    Linux2.0采用的解决办法是建立了13个空闲区链表,它们的大小从32字节到132056字节。从Linux2.2开始,MM的开发者采用了一种叫做slab的分配模式,该模式早在1994年就被开发出来,用于Sun Microsystem Solaris 2.4操作系统中。Slab的提出主要是基于以下考虑:

    1) 内核对内存区的分配取决于所存放数据的类型。例如,当给用户态进程分配页面时,内核调用get free page()函数,并用0填充这个页面。 而给内核的数据结构分配页面时,事情没有这么简单,例如,要对数据结构所在的内存进行初始化、在不用时要收回它们所占用的内存。因此,Slab中引入了对象这个概念,所谓对象就是存放一组数据结构的内存区,其方法就是构造或析构函数,构造函数用于初始化数据结构所在的内存区,而析构函数收回相应的内存区。但为了便于理解,你也可以把对象直接看作内核的数据结构。为了避免重复初始化对象,Slab分配模式并不丢弃已分配的对象,而是释放但把它们依然保留在内存中。当以后又要请求分配同一对象时,就可以从内存获取而不用进行初始化,这是在Solaris 中引入Slab的基本思想。

    实际上,Linux中对Slab分配模式有所改进,它对内存区的处理并不需要进行初始化或回收。出于效率的考虑,Linux并不调用对象的构造或析构函数,而是把指向这两个函数的指针都置为空。Linux中引入Slab的主要目的是为了减少对伙伴算法的调用次数。

    2) 实际上,内核经常反复使用某一内存区。例如,只要内核创建一个新的进程,就要为该进程相关的数据结构(task_struct、打开文件对象等)分配内存区。当进程结束时,收回这些内存区。因为进程的创建和撤销非常频繁,因此,Linux的早期版本把大量的时间花费在反复分配或回收这些内存区上。从Linux2.2开始,把那些频繁使用的页面保存在高速缓存中并重新使用。

    3) 可以根据对内存区的使用频率来对它分类。对于预期频繁使用的内存区,可以创建一组特定大小的专用缓冲区进行处理,以避免内碎片的产生。对于较少使用的内存区,可以创建一组通用缓冲区(如Linux2.0中所使用的2的幂次方)来处理,即使这种处理模式产生碎片,也对整个系统的性能影响不大。

    4) 硬件高速缓存的使用,又为尽量减少对伙伴算法的调用提供了另一个理由,因为对伙伴算法的每次调用都会“弄脏”硬件高速缓存,因此,这就增加了对内存的平均访问次数。

    Slab分配模式把对象分组放进缓冲区(尽管英文中使用了Cache这个词,但实际上指的是内存中的区域,而不是指硬件高速缓存)。因为缓冲区的组织和管理与硬件高速缓存的命中率密切相关,因此,Slab缓冲区并非由各个对象直接构成,而是由一连串的“大块(Slab)”构成,而每个大块中则包含了若干个同种类型的对象,这些对象或已被分配,或空闲,如图6.12所示。一般而言,对象分两种,一种是大对象,一种是小对象。所谓小对象,是指在一个页面中可以容纳下好几个对象的那种。例如,一个inode结构大约占300多个字节,因此,一个页面中可以容纳8个以上的inode结构,因此,inode结构就为小对象。Linux内核中把小于512字节的对象叫做小对象。实际上,缓冲区就是主存中的一片区域,把这片区域划分为多个块,每块就是一个Slab,每个Slab由一个或多个页面组成,每个Slab中存放的就是对象。

    2,通过slabtop命令查看slab缓存信息

    通过slabtop我们看到Linux系统中有大量的dentry cache占用内存,那dentry cache是什么呢?

    首先,我们知道inode对应于物理磁盘上的具体对象,而dentry是一个内存实体,其中的d inode成员指向对应的inode,故可以把dentry看成是Linux文件系统中某个索引节点(inode)的链接,这个索引节点可以是文件,也可以是目录。而dentry cache是目录项高速缓存,是Linux为了提高目录项对象的处理效率而设计的,它记录了目录项到inode的映射关系。

    3,结合storm服务分析

    当前服务器是storm集群的节点,首先想到了storm相关的工作进程,strace一下storm的worker进程发现其中有非常频繁的stat系统调用发生,而且stat的文件总是新的文件名:

    [@storm-yd8325 ~]# strace -fp 31984 -e trace=stat
    

    进一步观察到storm的worker进程会在本地目录下频繁的创建、打开、关闭、删除心跳文件,每秒钟一个新的文件名:

    [@storm-yd8325 ~]# sudo strace -fp 31984 -e trace=open,stat,close,unlink
    

    总结:storm进程频繁的文件io操作,导致了dentry_cache占用了系统太多的内存资源。

    4,系统的自动slab缓存回收

    在slab缓存中,对象分为SReclaimable(可回收)和SUnreclaim(不可回收),而在系统中绝大多数对象都是可回收的。内核有一个参数,当系统内存使用到一定量的时候,会自动触动回收操作。内核参数:

    vm.min_free_kbytes = 836787
    

    1)代表系统所保留空闲内存的最低限。

    在系统初始化时会根据内存大小计算一个默认值,计算规则是:

    min_free_kbytes = sqrt(lowmem_kbytes * 16) = 4 * sqrt(lowmem_kbytes)(注:lowmem_kbytes即可认为是系统内存大小)
    

    另外,计算出来的值有最小最大限制,最小为128K,最大为64M。

    可以看出,min free kbytes随着系统内存的增大不是线性增长,因为随着内存的增大,没有必要也线性的预留出过多的内存,能保证紧急时刻的使用量便足矣。

    2)min free kbytes的主要用途是计算影响内存回收的三个参数 watermark[min/low/high]

    (1) watermark[high] > watermark [low] > watermark[min],各个zone各一套

    (2)在系统空闲内存低于 watermark[low]时,开始启动内核线程kswapd进行内存回收(每个zone一个),直到该zone的空闲内存数量达到watermark[high]后停止回收。如果上层申请内存的速度太快,导致空闲内存降至watermark[min]后,内核就会进行direct reclaim(直接回收),即直接在应用程序的进程上下文中进行回收,再用回收上来的空闲页满足内存申请,因此实际会阻塞应用程序,带来一定的响应延迟,而且可能会触发系统OOM。这是因为watermark[min]以下的内存属于系统的自留内存,用以满足特殊使用,所以不会给用户态的普通申请来用。

    (3)三个watermark的计算方法:

    watermark[min] = min free kbytes换算为page单位即可,假设为min free pages。(因为是每个zone各有一套watermark参数,实际计算效果是根据各个zone大小所占内存总大小的比例,而算出来的per zone min free pages)

     watermark[low] = watermark[min] * 5 / 4
     watermark[high] = watermark[min] * 3 / 2
    

    所以中间的buffer量为 high - low = low - min = per_zone_min_free_pages * 1/4 。因为 min_free_kbytes = 4* sqrt(lowmem_kbytes) ,也可以看出中间的buffer量也是跟内存的增长速度成开方关系。

    (4)可以通过/proc/zoneinfo查看每个zone的watermark

    例如:

    Node 0, zone      DMA
    pages free     3960
           min      65
           low      81
           high     97
    

    3)min free kbytes大小的影响

    min_free_kbytes 设的越大,watermark的线越高,同时三个线之间的buffer量也相应会增加。这意味着会较早的启动kswapd进行回收,且会回收上来较多的内存(直至watermark[high]才会停止),这会使得系统预留过多的空闲内存,从而在一定程度上降低了应用程序可使用的内存量。极端情况下设置 min_free_kbytes 接近内存大小时,留给应用程序的内存就会太少而可能会频繁地导致OOM的发生。

    min_free_kbytes 设的过小,则会导致系统预留内存过小。kswapd回收的过程中也会有少量的内存分配行为(会设上PF_MEMALLOC)标志,这个标志会允许kswapd使用预留内存;另外一种情况是被OOM选中杀死的进程在退出过程中,如果需要申请内存也可以使用预留部分。这两种情况下让他们使用预留内存可以避免系统进入deadlock状态。

    5,最终结果

    最终查明, slab cache 占用过多属于正常问题,并且当内存到达系统最低空闲内存限制的话,会自动触发kswapd进程来回收内存,属于正常现象。

    注:测了一下,当调整完min free kbytes值大于系统空闲内存后,kswapd进程的确从休眠状态进入运行态,开始回收内存。

    根据我们跑的storm服务做出如下调整:

    vm.vfs_cache_pressure = 200
    

    该文件表示内核回收用于directory和inode cache内存的倾向;缺省值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比;降低该值低于100,将导致内核倾向于保留directory和inode cache;增加该值超过100,将导致内核倾向于回收directory和inode cache。


    
    


    展开全文
  • Linux 内存占用分析

    万次阅读 2018-02-08 11:10:46
    这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令;查看/proc/[pid]/下的文件。文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/下的文件内容进行了一些详细的介绍。...

    这篇博客主要介绍 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
    1
    2
    $ ps -aux | grep /usr/sbin/NetworkManager
    root 845 0.0 0.0 387084 13332 ? Ssl 3月28 0:00 /usr/sbin/NetworkManager --no-daemon
    1. 查看进程的所有线程

      1
      2
      3
      4
      5
      6
      $ 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
    2. 查看所有子进程

      1
      2
      3
      4
      5
      $ 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链表中。

    截取一行内容如下:

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

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

    vm_area_struct项maps项含义
    vm_start“-”前一列,如7f4e3f5ca000此段虚拟地址空间起始地址
    vm_end“-”后一列,如7f4e3f674000此段虚拟地址空间结束地址
    vm_flags第三列,如r-xp此段虚拟地址空间的属性。r:读,w:写,x:执行,p和s共用一个字段,互斥关系,p表示私有段,s表示共享段,如果没有相应权限,则用’-’代替
    vm_pgoff第四列,如00000000对有名映射,表示此段虚拟内存起始地址在文件中以页为单位的偏移。对匿名映射,它等于0或者vm_start/PAGE_SIZE
    vm_file->f_dentry->d_inode->i_sb->s_dev第五列,如08:02映射文件所属设备号。对匿名映射l来说,因为没有文件在磁盘上,所以没有设备号,始终为00:00。对有名映射来说,是映射的文件所在设备的设备号
    vm_file->f_dentry->d_inode->i_ino第六列,如525202映射文件所属节点号。对匿名映射来说,因为没有文件在磁盘上,所以没有节点号,始终为00:00。对有名映射来说,是映射的文件的节点号
     第七列,如/lib/ld-2.5.so对有名来说,是映射的文件名。对匿名映射来说,是此段虚拟内存在进程中的角色。[stack]表示在进程中作为栈使用,[heap]表示堆。其余情况则无显示

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

    smap 文件分析

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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页面如果没有交换机制的情况下,应该是不能回收的。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    #! /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 文件分析

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    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,摘取分析如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    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内存占用分析

    千次阅读 2017-03-16 21:23:52
    想必在Linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过top命令查看进程占用了多少内存。这里我们可以看到VIRT、RES...

    想必在Linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过top命令查看进程占用了多少内存。这里我们可以看到VIRT、RES和SHR三个重要的指标,他们分别代表什么意思呢?这是本文需要跟大家一起探讨的问题。当然如果更加深入一点,你可能会问进程所占用的那些物理内存都用在了哪些地方?这时候top命令可能不能给到你你所想要的答案了,不过我们可以分析proc文件系统提供的smaps文件,这个文件详尽地列出了当前进程所占用物理内存的使用情况。

        这篇blog总共分为三个部分。第一部分简要阐述虚拟内存和驻留内存这两个重要的概念;第二部分解释top命令中VIRT、RES以及SHR三个参数的实际参考意义;最后一部分向大家介绍一下smaps文件的格式,通过分析smaps文件我们可以详细了解进程物理内存的使用情况,比如mmap文件占用了多少空间、动态内存开辟消耗了多少空间、函数调用栈消耗了多少空间等等。

    关于内存的两个概念

          要理解top命令关于内存使用情况的输出,我们必须首先搞清楚虚拟内存(Virtual Memory)驻留内存(Resident Memory)两个概念。

    •  虚拟内存

       首先需要强调的是虚拟内存不同于物理内存,虽然两者都包含内存字眼但是它们属于两个不同层面的概念。进程占用虚拟内存空间大并非意味着程序的物理内存也一定占用很大。虚拟内存是操作系统内核为了对进程地址空间进行管理(process address space management)而精心设计的一个逻辑意义上的内存空间概念。我们程序中的指针其实都是这个虚拟内存空间中的地址。比如我们在写完一段C++程序之后都需要采用g++进行编译,这时候编译器采用的地址其实就是虚拟内存空间的地址。因为这时候程序还没有运行,何谈物理内存空间地址?凡是程序运行过程中可能需要用到的指令或者数据都必须在虚拟内存空间中。既然说虚拟内存是一个逻辑意义上(假象的)的内存空间,为了能够让程序在物理机器上运行,那么必须有一套机制可以让这些假象的虚拟内存空间映射到物理内存空间(实实在在的RAM内存条上的空间)。这其实就是操作系统中页映射表(page table)所做的事情了。内核会为系统中每一个进程维护一份相互独立的页映射表。。页映射表的基本原理是将程序运行过程中需要访问的一段虚拟内存空间通过页映射表映射到一段物理内存空间上,这样CPU访问对应虚拟内存地址的时候就可以通过这种查找页映射表的机制访问物理内存上的某个对应的地址。“页(page)”是虚拟内存空间向物理内存空间映射的基本单元。

            下图1演示了虚拟内存空间和物理内存空间的相互关系,它们通过Page Table关联起来。其中虚拟内存空间中着色的部分分别被映射到物理内存空间对应相同着色的部分。而虚拟内存空间中灰色的部分表示在物理内存空间中没有与之对应的部分,也就是说灰色部分没有被映射到物理内存空间中。这么做也是本着“按需映射”的指导思想,因为虚拟内存空间很大,可能其中很多部分在一次程序运行过程中根本不需要访问,所以也就没有必要将虚拟内存空间中的这些部分映射到物理内存空间上。

            到这里为止已经基本阐述了什么是虚拟内存了。总结一下就是,虚拟内存是一个假象的内存空间,在程序运行过程中虚拟内存空间中需要被访问的部分会被映射到物理内存空间中。虚拟内存空间大只能表示程序运行过程中可访问的空间比较大,不代表物理内存空间占用也大。

                      图1. 虚拟内存空间到物理内存空间映射

    •  驻留内存

      驻留内存,顾名思义是指那些被映射到进程虚拟内存空间的物理内存。上图1中,在系统物理内存空间中被着色的部分都是驻留内存。比如,A1、A2、A3和A4是进程A的驻留内存;B1、B2和B3是进程B的驻留内存。进程的驻留内存就是进程实实在在占用的物理内存。一般我们所讲的进程占用了多少内存,其实就是说的占用了多少驻留内存而不是多少虚拟内存。因为虚拟内存大并不意味着占用的物理内存大。

      关于虚拟内存和驻留内存这两个概念我们说到这里。下面一部分我们来看看top命令中VIRT、RES和SHR分别代表什么意思。

    top命令中VIRT、RES和SHR的含义

         搞清楚了虚拟内存的概念之后解释VIRT的含义就很简单了。VIRT表示的是进程虚拟内存空间大小。对应到图1中的进程A来说就是A1、A2、A3、A4以及灰色部分所有空间的总和。也就是说VIRT包含了在已经映射到物理内存空间的部分和尚未映射到物理内存空间的部分总和。

      RES的含义是指进程虚拟内存空间中已经映射到物理内存空间的那部分的大小。对应到图1中的进程A来说就是A1、A2、A3以及A4几个部分空间的总和。所以说,看进程在运行过程中占用了多少内存应该看RES的值而不是VIRT的值。

      最后来看看SHR所表示的含义。SHR是share(共享)的缩写,它表示的是进程占用的共享内存大小。在上图1中我们看到进程A虚拟内存空间中的A4和进程B虚拟内存空间中的B3都映射到了物理内存空间的A4/B3部分。咋一看很奇怪。为什么会出现这样的情况呢?其实我们写的程序会依赖于很多外部的动态库(.so),比如libc.so、libld.so等等。这些动态库在内存中仅仅会保存/映射一份,如果某个进程运行时需要这个动态库,那么动态加载器会将这块内存映射到对应进程的虚拟内存空间中。多个进展之间通过共享内存的方式相互通信也会出现这样的情况。这么一来,就会出现不同进程的虚拟内存空间会映射到相同的物理内存空间。这部分物理内存空间其实是被多个进程所共享的,所以我们将他们称为共享内存,用SHR来表示。某个进程占用的内存除了和别的进程共享的内存之外就是自己的独占内存了。所以要计算进程独占内存的大小只要用RES的值减去SHR值即可。

    进程的smaps文件

      通过top命令我们已经能看出进程的虚拟空间大小(VIRT)、占用的物理内存(RES)以及和其他进程共享的内存(SHR)。但是仅此而已,如果我想知道如下问题:

    1. 进程的虚拟内存空间的分布情况,比如heap占用了多少空间、文件映射(mmap)占用了多少空间、stack占用了多少空间?
    2. 进程是否有被交换到swap空间的内存,如果有,被交换出去的大小?
    3. mmap方式打开的数据文件有多少页在内存中是脏页(dirty page)没有被写回到磁盘的?
    4. mmap方式打开的数据文件当前有多少页面已经在内存中,有多少页面还在磁盘中没有加载到page cahe中?
    5. 等等

      以上这些问题都无法通过top命令给出答案,但是有时候这些问题正是我们在对程序进行性能瓶颈分析和优化时所需要回答的问题。所幸的是,世界上解决问题的方法总比问题本身要多得多。linux通过proc文件系统为每个进程都提供了一个smaps文件,通过分析该文件我们就可以一一回答以上提出的问题。

      在smaps文件中,每一条记录(如下图2所示)表示进程虚拟内存空间中一块连续的区域。其中第一行从左到右依次表示地址范围、权限标识、映射文件偏移、设备号、inode、文件路径。详细解释可以参见understanding-linux-proc-id-maps

      接下来8个字段的含义分别如下:

    • Size:表示该映射区域在虚拟内存空间中的大小。
    • Rss:表示该映射区域当前在物理内存中占用了多少空间      
    • Shared_Clean:和其他进程共享的未被改写的page的大小
    • Shared_Dirty: 和其他进程共享的被改写的page的大小
    • Private_Clean:未被改写的私有页面的大小。
    • Private_Dirty: 已被改写的私有页面的大小。
    • Swap:表示非mmap内存(也叫anonymous memory,比如malloc动态分配出来的内存)由于物理内存不足被swap到交换空间的大小。
    • Pss:该虚拟内存区域平摊计算后使用的物理内存大小(有些内存会和其他进程共享,例如mmap进来的)。比如该区域所映射的物理内存部分同时也被另一个进程映射了,且该部分物理内存的大小为1000KB,那么该进程分摊其中一半的内存,即Pss=500KB。

                                图2. smaps文件中的一条记录

      有了smap如此详细关于虚拟内存空间到物理内存空间的映射信息,相信大家已经能够通过分析该文件回答上面提出的4个问题。

      最后希望所有读者能够通过阅读本文对进程的虚拟内存和物理内存有一个更加清晰认识,并能更加准确理解top命令关于内存的输出,最后可以通过smaps文件更进一步分析进程使用内存的情况。

    展开全文
  • linux 进程内存占用分析

    万次阅读 2018-06-11 16:19:36
    通过free命令可以查看系统内存使用情况: free -m total used free shared buff/cache available Mem: 7983 2427 5155 26 400 5272 Swap: ...
  • Linux/Unix与windows在管理内存的方式上是不一样的。它的管理方式是充分的利用系统...但是,这个内存占用量不会达到100%的,因为当达到一个占用量的时候,就会启用swap(虚拟内存)。(关于为何会使用高的解释:a、lin...
  • 这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令;查看/proc/[pid]/下的文件。文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/下的文件内容进行了一些详细的介绍。文章...
  • 为什么80%的码农都做不了架构师?>>> ...
  • linux内存占用详细统计分析

    千次阅读 2018-09-07 12:05:16
    linux内存占用 linux内存占用通过free来查看 但是具体由哪些地方占用了呢 大致分为4类:rss、pagetable、slabinfo、HugePages   ps aux --sort=-rss|grep -v RSS|awk '{s=s+$6}END{print s/1024"MB"...
  • linux内存实际占用分析

    千次阅读 2018-07-27 18:07:23
    作者: 黄永兵/译 出处:51CTO.com 阅读提示:本文是为那些经常疑惑的人准备的,“为什么一个简单的KDE文本编辑器要占用25M内存?”导致大多数人认为许多Linux应用程序,特别是KDE或GNOME程序都象ps报告一样臃肿......
  • 这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令;查看/proc/[pid]/下的文件。文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/下的文件内容进行了一些详细的介绍。文章...
  • 分析1、linux系统内存消耗主要有三个地方:进程slabpagecacge用 free 命令查看到的是系统整体的内容使用情况,而使用 ps 和 top 看到的内存使用情况都是以进程维度来看的,因此看不到 slabcache 和pagec...
  • Linux内存占用情况分析

    千次阅读 2015-08-17 12:08:04
    Linux下如何查内存信息,如内存总量、已使用量、可使用量。 经常使用Windows操作系统的朋友,已经习惯了如果空闲的内存较多,心里比较踏实。 当使用Linux时,可能觉的Linux物理内存很快被用光(如频繁存取文件后)...
  • 可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令:1、toptop命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务...
  • 查看LINUX进程内存占用情况 参考博文: 查看LINUX进程内存占用情况 可以直接使用top命令后,查看%MEM的内容。可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令: ...
  • 而当我们使用free命令查看Linux系统内存使用情况时,会 发现内存使用一直处于较高的水平,即使此时系统并没有运行多少软件。这正是Windows和Linux内存管理上的区别,乍一看,Linux系统吃掉我...
  • 一、背景搜索引擎中,使用内存映射的方式加载庞大的索引数据文件已是常态,58自研的搜索引擎ESearch也是如此。ESearch检索节点中,索引数据是分段存储的,段上正排倒排等数据又分别存储在不同文件上,所有索引数据都...
  • 可以选择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况的话可以使用如下的命令:1、toptop命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务...
  • free -g 实际内存占用要看-/+ buffers/cache行 参看: 正确理解Linux内存占用过高的问题 linux 系统内存占用 90%以上解决办法 ...linux 内存占用过大分析 Linux下Oracle进程CPU使用率过高处理方式 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,342
精华内容 536
关键字:

linux分析内存占用

linux 订阅