在Linux产品开发过程中,通常需要注意系统内存使用量,和评估单一进程的内存使用情况,便于我们选取合适的机器配置,来部署我们的产品。

Linux本身提供了一些工具方便我们达成这些需求,查看进程实时资源top工具,更详细的进程内存堆栈情况,pmap工具,Linux进程运行时状态信息也会保存在proc目录下,相应进程ID目录下,这里有很丰富的信息,先讨论进程内存。

   借助网上大部分人的说法,Linux系统在内存分配上:内存充足时,尽量使用内存来缓存一些文件,从而加快进程的运行速度,而当内存不足时,会通过相应的内存回收策略收回cache内存,供进程使用。

虽然在Linux平台下做开发,但是对Linux内存管理并不熟悉,不过上述说法,可以通过下面的方法来验证:

一、系统内存。

在proc目录下的meminfo文件描述系统内存的使用情况,可用的物理内存=memfree+buffers+cached,下图是suse10 的情况:

MemTotal 是全部物理内存,我的虚拟器配置的是1G内存,memfree+buffers+cached = 438752,大概还有430M可用,因为我的机器上只跑着apache和redis进程。

当memfree不够时,内核会通过回写机制(pdflush线程)把cached和buffered内存回写到后备存储器,也可以通过手动方式显式释放cache内存

echo 3 > /proc/sys/vm/drop_caches

释放后,Buffers和Cached 表小了好多,MemFree变大了许多,memfree+buffers+cached三者和大约仍然是430M。

二、进程内存

在32位操作系统中,每个进程拥有4G的虚拟内存空间,其中0~3GB是每个进程的私有用户空间,这个空间对系统中其他进程是不可见的。3~4GB是linux内核空间,由系统所有的进程以及内核所共享的。通过访问/proc/{pid}/下相关文件,可以查看进程内存情况。

如果进程内含有多个线程,多个线程共享一个进程的用户态虚拟地址空间,虚拟地址空间包含若干区域,主要有如下几个区域:

1、当前执行文件的代码段,该代码段称为text段。

2、执行文件的数据段,主要存储执行文件用到的全局变量,静态变量。(全局和static)

3、存储全局变量和动态产生的数据的堆。(堆)

4、用于保存局部变量和实现函数调用的栈。(栈)

5、采用mmap方式映射到虚拟地址空间中的内存段

这是我的机器上,redis 进程的情况,

第一行:从r-xp可知其权限为只读、可执行,该段内存地址对应于执行文件的

代码段,程序的代码段需加载到内存中才可以执行。由于其只读,不会

被修改,所以在整个系统内共享。

第二行:从rw-p可知其权限为可读写,不可执行,该段内存地址对应于执行文件的数据段,存放执行文件所用到的全局变量、静态变量。

第三行:从rwxp可知其权限是可读写,可执行,地址空间向上增长,而且不对应文件,是堆段,进程使用malloc申请的内存放在堆段。每个进程只有一个堆段,不论是主进程,还是不同的线程申请的内存,都反映到到进程的堆段。堆段向上增长,最大可以增长到1GB的位置,即0x40000000,如果大于1GB,glibc将采用mmap的方式,为堆申请一块内存。

第四行:是程序连接的共享库的内存地址。

第五行:是以mmap方式映射的虚拟地址空间。

第六、七行:是线程的栈区地址段,每个线程的栈大小都是16K。

第八行:是进程的栈区。关于栈段,每个线程都有一个,如果进程中有多个线程,则包含多个栈段。

三、当前系统总内存的统计

1、进程占用的总内存可以通过上述maps表计算出来。

2、当系统运行起来以后,会把应用层相关的文件挂载到tmpfs文件系统下,海思系统下这部分大概有13M左右,这部分内存是以cache方式统计出来的,但是这部分内存cache无法通过回收策略或者显式的调用释放掉。

3、根文件系统ramdisk占用的内存。

4、当前系统保留内存的大小,可以通过查看/proc/sys/vm/min_free_kbytes来获取或者修改此内存的大小。

5、当然,当系统运行起来后,还应该留有一定的内存用于在硬盘读写时做cache或者网络负荷比较高时分配skb等,一般需要30M以上。

四、对调试内存泄露类问题的一些启示

当进程申请内存时,实际上是glibc中内置的内存管理器接收了该请求,随着进程申请内存的增加,内存管理器会通过系统调用陷入内核,从而为进程分配更多的内存。

针对堆段的管理,内核提供了两个系统调用brk和mmap,brk用于更改堆顶地址,而mmap则为进程分配一块虚拟地址空间。

当进程向glibc申请内存时,如果申请内存的数量大于一个阀值的时候,glibc会采用mmap为进程分配一块虚拟地址空间,而不是采用brk来扩展堆顶的指针。缺省情况下,此阀值是128K,可以通过函数来修改此值。

#include<malloc.h>

Intmallopt(int param, int value)

Param的取值分别为M_MMAP_THRESHOLD、M_MMAP_MAX。

Value的取值是以字节为单位的。

M_MMAP_THRESHOLD是glibc中申请大块内存阀值,大于该阀值的内存申请,内存管理器将使用mmap系统调用申请内存,如果小于该阀值的内存申请,内存管理器使用brk系统调用扩展堆顶指针。

M_MMAP_MAX是该进程中最多使用mmap分配地址段的数量。

如果在实际的调试过程中,怀疑某处发生了内存泄露,可以查看该进程的maps表,看进程的堆段或者mmap段的虚拟地址空间是否持续增加,如果是,说明很可能发生了内存泄露,如果mmap段虚拟地址空间持续增加,还可以看到各个段的虚拟地址空间的大小,从而可以确定是申请了多大的内存,对调试内存泄露类问题可以起到很好的定位作用。

转自:http://blog.csdn.net/babykakaluo/article/details/9763605

Linux进程内存分析和内存泄漏定位的更多相关文章

  1. 关于redis内存分析,内存优化

    对于redis来说,什么是最重要的? 毋庸置疑,是内存. 一.reids 内存分析 redis内存使用情况:info memory 示例: 可以看到,当前节点内存碎片率为226893824/20952 ...

  2. iOS的内存分析和内存管理

    iOS的内存分析和内存管理 [内存管理]一直是iOS开发中的一个重点. 本文就带你从内存分析开始一步步了解内存的占用情况,从真实的情况中领悟真正项目开发过程中的内存的使用情况. 注:本文默认你熟悉 M ...

  3. Linux 进程通信(共享内存区)

    共享内存是由内核出于在多个进程间交换信息的目的而留出的一块内存区(段). 如果段的权限设置恰当,每个要访问该段内存的进程都可以把它映像到自己的私有地址空间中. 如果一个进程更新了段中的数据,其他进程也 ...

  4. linux 进程通信之 共享内存

    共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...

  5. 从linux进程角度看JVM内存模型

    普通进程栈区,在JVM一般仅仅用做线程栈,如下图所示 首先是永久代.永久代本质上是Java程序的代码区和数据区.Java程序中类(class),会被加载到整个区域的不同数据结构中去,包括常量池.域.方 ...

  6. linux进程通信之共享内存

    共享内存同意两个或多个进程共享一给定的存储区,由于数据不须要来回复制,所以是最快的一种进程间通信机制.共享内存能够通过mmap()映射普通文件(特殊情况下还能够採用匿名映射)机制实现,也能够通过系统V ...

  7. linux 进程学习笔记-共享内存

    如果能划定一块物理内存,让多个进程都能将该内存映射到其自身虚拟内存空间的话,那么进程可以通过向这块内存空间读写数据而达到通信的目的.另外,和消息队列不同的是,共享的内存在用户空间而不是核空间,那么就不 ...

  8. Linux进程通信之共享内存实现生产者/消费者模式

    共享内存 共享内存是内核为进程创建的一个特殊内存段,它将出现在进程自己的地址空间中,其它进程可以将同一段共享内存连接(attach)到自己的地址空间.这是最快的进程间通信方式,但是不提供任何同步功能( ...

  9. Linux 进程通信之:内存共享(Shared Memory)(转,好文章)

    https://blog.csdn.net/afei__/article/details/84188548

随机推荐

  1. numpy.meshgrid()

    numpy提供的numpy.meshgrid()函数可以让我们快速生成坐标矩阵X,Y 语法:X,Y = numpy.meshgrid(x, y)输入:x,y,就是网格点的横纵坐标列向量(非矩阵)输出: ...

  2. Deeplab v3+的结构代码简要分析

    添加了解码模块来重构精确的图像物体边界.对比如图 deeplab v3+采用了与deeplab v3类似的多尺度带洞卷积结构ASPP,然后通过上采样,以及与不同卷积层相拼接,最终经过卷积以及上采样得到 ...

  3. Eclipse修改编码方式

    1.修改工作空间默认编码 1.修改工作空间默认编码:window -> preferences ->  General -> Workspace 2.修改文件的编码 在Eclipse ...

  4. jQuery事件--keypress([[data],fn])和trigger(type,[data])

    keypress([[data],fn]) 概述 当键盘或按钮被按下时,发生 keypress 事件 keypress 事件与 keydown 事件类似.当按钮被按下时,会发生该事件.它发生在当前获得 ...

  5. uva 1416 Warfare And Logistics

    题意: 给出一个无向图,定义这个无向图的花费是 其中path(i,j),是i到j的最短路. 去掉其中一条边之后,花费为c’,问c’ – c的最大值,输出c和c’. 思路: 枚举每条边,每次把这条边去掉 ...

  6. MySql语句分类

    SQL语言分为四大类:数据定义语言DDL,数据查询语言DQL,数据操作语言DML,数据控制语言DCL [1]数据定义语言DDL 数据定义语言DDL,用于创建.修改.删除数据库内的数据结构.如下: (1 ...

  7. 关于SQL语句中的distinct和group by

    两种都能实现去重功能.区别: distinct只是将重复的行从结果中出去: group by是按指定的列分组,一般这时在select中会用到聚合函数. distinct是把不同的记录显示出来 grou ...

  8. 设计模式之Composite(组合)(转)

    Composite定义: 将对象以树形结构组织起来,以达成"部分-整体" 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Comp ...

  9. [转]Hive开发经验问答式总结

    本文转载自:http://www.crazyant.net/1625.html 本文是自己开发Hive经验的总结,希望对大家有所帮助,有问题请留言交流. Hive开发经验思维导图 Hive开发经验总结 ...

  10. selenium-java web自动化测试工具抓取百度搜索结果实例

    selenium-java web自动化测试工具抓取百度搜索结果实例 这种方式抓百度的搜索关键字结果非常容易抓长尾关键词,根据热门关键词去抓更多内容可以用抓google,百度的这种内容容易给屏蔽,用这 ...