Linux虚拟内存介绍,以及malloc_stats和malloc_info 监控查看内存情况

zzhongcy 2019-04-09 10:33:08 3106 已收藏 3
分类专栏: Linux
版权
查找内存泄漏问题,可以使用valgrind、malloc_stats和malloc_info 监控查看内存情况。

1、 Linux内存介绍
1.1 Linux 的虚拟内存管理有几个关键概念:
1、每个进程都有独立的虚拟地址空间,进程访问的虚拟地址并不是真正的物理地址;
2、虚拟地址可通过每个进程上的页表(在每个进程的内核虚拟地址空间)与物理地址进行映射,获得真正物理地址;
3、如果虚拟地址对应物理地址不在物理内存中,则产生缺页中断,真正分配物理地址,同时更新进程的页表;如果此时物理内存已耗尽,则根据内存替换算法淘汰部分页面至物理磁盘中。

1.2、Linux 虚拟地址空间如何分布?
Linux 使用虚拟地址空间,大大增加了进程的寻址空间,由低地址到高地址分别为:
1、只读段:该部分空间只能读,不可写;(包括:代码段、rodata 段(C常量字符串和#define定义的常量) )
2、数据段:保存全局变量、静态变量的空间;
3、堆 :就是平时所说的动态内存, malloc/new 大部分都来源于此。其中堆顶的位置可通过函数 brk 和 sbrk 进行动态调整。
4、文件映射区域 :如动态库、共享内存等映射物理空间的内存,一般是 mmap 函数所分配的虚拟地址空间。
5、栈:用于维护函数调用的上下文空间,一般为 8M ,可通过 ulimit –s 查看。
6、内核虚拟空间:用户代码不可见的内存区域,由内核管理(页表就存放在内核虚拟空间)。

1.3 32 位系统有4G 的地址空间::
其中 0x08048000~0xbfffffff 是用户空间,0xc0000000~0xffffffff 是内核空间,包括内核代码和数据、与进程相关的数据结构(如页表、内核栈)等。另外,%esp 执行栈顶,往低地址方向变化;brk/sbrk 函数控制堆顶_edata往高地址方向变化。

1.4 64位系统结果怎样呢? 64 位系统是否拥有 2^64 的地址空间吗?
事实上, 64 位系统的虚拟地址空间划分发生了改变:
1、地址空间大小不是232,也不是264,而一般是2^48。因为并不需要 2^64 这么大的寻址空间,过大空间只会导致资源的浪费。64位Linux一般使用48位来表示虚拟地址空间,40位表示物理地址,这可通过 /proc/cpuinfo 来查看
address sizes : 40 bits physical, 48 bits virtual

  2、其中,0x0000000000000000~0x00007fffffffffff 表示用户空间, 0xFFFF800000000000~ 0xFFFFFFFFFFFFFFFF 表示内核空间,共提供 256TB(2^48) 的寻址空间。这两个区间的特点是,第 47 位与 48~63 位相同,若这些位为 0 表示用户空间,否则表示内核空间。 3、用户空间由低地址到高地址仍然是只读段、数据段、堆、文件映射区域和栈;

2、 valgrind
valgrind可以用来检测内存泄露,但在使用中,往往会遇到一些问题,给调试工作带来很多不必要的麻烦,我自己遇到的有以下两种:

  (1)内存泄露误检(系统初始化时,可能有一些需要长期保存在内存中的数据结构,这些空间是永远不释放的,而这些内存会被认为绝对泄露)(2) valgrind检查内存泄露过于全面,运行后的结果太多往往很难从中找到有用的信息。有时候,我们只需要关注某些函数,可能在执行某个操作,调用某些函数时会出现内存泄露,此时,valgrind的工作显得冗余而复杂

3、 mallinfo
mallinfo函数已不推荐使用,并且都不再更新。

可以添加代码到程序:

#include <malloc.h>
#include <stdio.h>
void dumpMallinfo(void) {
struct mallinfo m = mallinfo();
printf(“uordblks = %dnfordblks = %dn”, m.uordblks, m.fordblks);
}
在GDB,可以 call dumpMallinfo().

4、 malloc_stats
系统库函数中提供了malloc_stats()函数,可以统计本进程具体的内存使用情况,精确到字节。

glibc 提供了以下结构和接口来查看堆内内存和 mmap 的使用情况。

struct mallinfo {
int arena; /* non-mmapped space allocated from system /
int ordblks; /
number of free chunks /
int smblks; /
number of fastbin blocks /
int hblks; /
number of mmapped regions /
int hblkhd; /
space in mmapped regions /
int usmblks; /
maximum total allocated space /
int fsmblks; /
space available in freed fastbin blocks /
int uordblks; /
total allocated space /
int fordblks; /
total free space /
int keepcost; /
top-most, releasable (via malloc_trim) space */
};

/*返回heap(main_arena)的内存使用情况,以 mallinfo 结构返回 */
struct mallinfo mallinfo();

/* 将heap和mmap的使用情况输出到stderr*/
void malloc_stats();

4.1 gdb内部调试
call malloc_stats()
(gdb) call malloc_stats()
Arena 0:
system bytes = 135168
in use bytes = 96
Total (incl. mmap):
system bytes = 135168
in use bytes = 96
max mmap regions = 0
max mmap bytes = 0
call malloc_info(0, stdout)
(gdb) call malloc_info(0, stdout)

<system type=“current” size="135168
/>
<system type=“max” size="135168
/>

4.2 gdb外部调试
根据 malloc_stats()的手册手册,内存信息被发送到标准错误。 一般输出到stderr 。

命名:

gdb --batch --pid --ex ‘call malloc_stats()’
查看stderr.log:


MALLOC: 11159496 ( 10.6 MiB) Bytes in use by application
MALLOC: + 1769472 ( 1.7 MiB) Bytes in page heap freelist
MALLOC: + 3580792 ( 3.4 MiB) Bytes in central cache freelist
MALLOC: + 1998848 ( 1.9 MiB) Bytes in transfer cache freelist
MALLOC: + 19240128 ( 18.3 MiB) Bytes in thread cache freelists
MALLOC: + 1379480 ( 1.3 MiB) Bytes in malloc metadata
MALLOC: ------------
MALLOC: = 39128216 ( 37.3 MiB) Actual memory used (physical + swap)
MALLOC: + 0 ( 0.0 MiB) Bytes released to OS (aka unmapped)
MALLOC: ------------
MALLOC: = 39128216 ( 37.3 MiB) Virtual address space used
MALLOC:
MALLOC: 810 Spans in use
MALLOC: 157 Thread heaps in use
MALLOC: 32768 Tcmalloc page size

Call ReleaseFreeMemory() to release freelist memory to the OS (via madvise()).
Bytes released to the OS take up virtual address space but no physical memory.
4.3 其他
如果默认编译,使用的是libc的ptmalloc内存分配器库,这个库可能有一定的内存碎片问题,我们线上也有遇到过,见comment最后
任然无法查出,得上通用的内存分配扫描工具 。比如systap脚本抓取malloc/free的栈记录,然后分析记录信息查看。比如valgrind --mem-leak(往上可以搜索方法, 注意)
4.3.1 glibc库的ptmalloc2信息采集:
强制nginx worker调用malloc_stats()函数,让其将数据输出到stderr(nginx重定向到error.log)

$ gdb -p $(pgrep -P $(cat logs/nginx.pid)) -ex ‘call malloc_stats()’

error.log内dump出来的信息

Arena 0: <<< 线程 0(一般tengine worker内只有1个thread)
system bytes = 1372160 <<< 从os抽取的内存(一般为mmap)
in use bytes = 1198448 <<< 应用程序malloc的
Total (incl. mmap):
system bytes = 1372160
in use bytes = 1198448
max mmap regions = 6
max mmap bytes = 2789376
4.3.2 for jemalloc:
$ gdb -batch -p -ex ‘call malloc_stats_print(0,0,0)’
如果想知道堆内片究竟有多碎 ,可通过 mallinfo 结构中的 fsmblks 、 smblks 、 ordblks值得到,这些值表示不同大小区间的碎片总个数,这些区间分别是 0~80 字节, 80~512 字节,512~128k 。如果 fsmblks 、 smblks 的值过大,那碎片问题可能比较严重了。

  不过, mallinfo 结构有一个很致命的问题,就是其成员定义全部都是 int ,在 64 位环境中,其结构中的 uordblks/fordblks/arena/usmblks 很容易就会导致溢出,应该是历史遗留问题,使用时要注意!

5、 除了 glibc 的 malloc/free ,还有其他第三方实现吗?
其实,很多人开始诟病 glibc 内存管理的实现,就是在高并发性能低下和内存碎片化问题都比较严重,因此,陆续出现一些第三方工具来替换 glibc 的实现,最著名的当属 google 的tcmalloc 和 facebook 的 jemalloc 。网上有很多资源,可搜索之,这里就不详述了。

6、 既然堆内内存brk和sbrk不能直接释放,为什么不全部使用 mmap 来分配,munmap直接释放呢?
既然堆内碎片不能直接释放,导致疑似“内存泄露”问题,为什么 malloc 不全部使用 mmap 来实现呢(mmap分配的内存可以会通过 munmap 进行 free ,实现真正释放)?而是仅仅对于大于 128k 的大块内存才使用 mmap ?

    其实,进程向 OS 申请和释放地址空间的接口 sbrk/mmap/munmap 都是系统调用,频繁调用系统调用都比较消耗系统资源的。并且, mmap 申请的内存被 munmap 后,重新申请会产生更多的缺页中断。例如使用 mmap 分配 1M 空间,第一次调用产生了大量缺页中断 (1M/4K 次 ) ,当munmap 后再次分配 1M 空间,会再次产生大量缺页中断。缺页中断是内核行为,会导致内核态CPU消耗较大。另外,如果使用 mmap 分配小内存,会导致地址空间的分片更多,内核的管理负担更大。同时堆是一个连续空间,并且堆内碎片由于没有归还 OS ,如果可重用碎片,再次访问该内存很可能不需产生任何系统调用和缺页中断,这将大大降低 CPU 的消耗。 因此, glibc 的 malloc 实现中,充分考虑了 sbrk 和 mmap 行为上的差异及优缺点,默认分配大块内存 (128k) 才使用 mmap 获得地址空间,也可通过 mallopt(M_MMAP_THRESHOLD, <SIZE>) 来修改这个临界值。

malloc系统有自己的内存池管理策略:
1、malloc的时候,检测池中是否有足够内存,有则直接分配,无则从内存中调用brk/mmap函数分配,一般小于等于128k(可设置)的内存,使用brk函数,此时堆向上(有人有的硬件或系统向下)增长,大于128k的内存使用mmap函数申请,此时堆的位置任意,无固定增长方向。

 2、free的时候,检测标记是否是mmap申请,是则调用unmmap归还给操作系统,非则检测堆顶是否有大于128k的空间,有则通过brk归还给操作系统,无则标记未使用,仍在glibc的管理下。glibc为申请的内存存储多余的结构用于管理,因此即使是malloc(0),也会申请出内存(一般16字节,依赖于malloc的实现方式),在应用程序层面,malloc(0)申请出的内存大小是0,因为malloc返回的时候在实际的内存地址上加了16个字节偏移,而c99标准则规定malloc(0)的返回行为未定义。除了内存块头域,malloc系统还有红黑树结构保存内存块信息,不同的实现又有不同的分配策略。频繁直接调用malloc,会增加内存碎片,增加和内核态交互的可能性,降低系统性能。

7、如何查看进程的缺页中断信息?
可通过以下命令查看缺页中断信息

ps -o majflt,minflt -C <program_name>
ps -o majflt,minflt -p
MAJFLT MINFLT
0 27698
其中:: majflt 代表 major fault ,指大错误; minflt 代表 minor fault ,指小错误。

这两个数值表示一个进程自启动以来所发生的缺页中断的次数。
其中 majflt 与 minflt 的不同是:majflt 表示需要读写磁盘,可能是内存对应页面在磁盘中需要load 到物理内存中,也可能是此时物理内存不足,需要淘汰部分物理页面至磁盘中。

参考:

https://github.com/alibaba/tengine/issues/1043

https://blog.csdn.net/origin_lee/article/details/42740535

http://landcareweb.com/questions/20566/jian-cha-gdbzhong-de-c-c-dui-nei-cun-tong-ji-xin-xi

Linux虚拟内存介绍,以及malloc_stats和malloc_info 监控查看内存情况相关推荐

  1. linux umount swap,挂载、卸载、free查看内存情况、创建交换分区、回环设备、dd命令、自动挂载、fuser...

    挂载.卸载 分区.格式化创建了文件系统后就可以挂载了 挂载:将新的文件系统关联至当前根文件系统 卸载:将某文件系统与当前根文件系统的关联关系移除 mount挂载 使用方法: mount 设备 挂载点 ...

  2. linux free命令详解和使用实例(查看内存使用率)

    free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存,及被内核使用的buffer.在Linux系统监控的工具中,free命令是最经常使用的命令之一 1.命令格式: free [参数 ...

  3. mrtg监控linux主机的甚至,windows上mrtg监控linuxcpu 内存

    *网上95%都是linux安装mrtg来做监控,windows来做监控机的很少,即使用也是轻轻点水很肤浅,下面是我亲自在windows上安装mrtg来做监控机的实验,并且也已经开始运行在企业当中.mr ...

  4. Linux上使用shell脚本查看内存情况(超实用)

    #!/bin/bash# tomcat启动程序(这里注意tomcat实际安装的路径) StartTomcat=/wls/jenkins/apache-tomcat-6.0.39/bin/startup ...

  5. linux目录介绍和命令总结(后期续更)

    为什么需要使用linux操作系统? 性能问题:windows服务器操作系统不如linux高 稳定性问题: 底层架构:linux更加稳定,其开机时间可以达到好几年不关机 开源:因为开源,人人都可以看到源 ...

  6. 安装Java Visualvm监控堆内存和参数说明

    安装Java Visualvm监控堆内存和参数说明 1.概述 这篇文章介绍使用Java Visualvm工具监控堆内存VisualGC插件的安装以及监控堆内存参数说明. 摘要 VisualGC插件安装 ...

  7. linux怎么查看证书库,curl --resolve 查看证书情况

    通过curl  解析证书 [root@harbor ~]# curl --resolve 'www.abc.com:127.0.0.1' https://www.abc.com/ -vvv * Cou ...

  8. Linux运维:CentOS7下查看内存占用

    文章目录 查看主机信息 查看操作系统信息 查看Linux系统版本 查看物理CPU个数和型号 查看单个物理CPU核心数 查看逻辑CPU个数 查看内存信息 查看内存情况 查看内存剩余情况 内存使用排序取前 ...

  9. 操作系统:Linux虚拟内存知识介绍

    今天给大家分享Linux虚拟内存相关的知识,希望的对大家能有所帮助! 1.虚拟内存 毋庸置疑,虚拟内存是操作系统中最重要的概念之一.我想主要是由于内存的重要"战略地位".CPU太快 ...

最新文章

  1. CentOS7 打包RPM 升级OpenSSH8.3
  2. 微信公众号开发之微信JSSDK
  3. Linux下C语言编程入门-14关于网络编程(1)TCP
  4. 服务器自动安全审计,用于Linux服务器的自动安全审计工具
  5. 播放图像有锯齿_反隔行操作
  6. [JavaWeb-Servlet]概述与快速入门
  7. Spotify如何使用Cassandra实现个性化推荐
  8. java阿里云短信服务开通验证码功能实现(1)
  9. __attribute__((unused)):可能不会用到,消除编译警告
  10. css3实现 依次出现三个点(一般用于提示加载中。。。 提交中。。。)
  11. 线上只执行一次的脚本编写注意事项
  12. java转换字符串编码格式_java转换字符串编码格式的方法
  13. 机器人语音---走进优必选
  14. 日语中阴历月份的别称
  15. FireFox精彩电视广告欣赏
  16. Swift --- 扩展(Extention)
  17. 百宝箱-Rime配置
  18. libvirt 的使用
  19. 二叉树的讲解《二》(二叉树实现堆)
  20. android开源项目---View篇

热门文章

  1. 文哥做了个古玩大富翁游戏
  2. 用友U8车间管理案例专题一
  3. 计算机组装接线口诀,2016年机电一级建造师_一、三章案例 口诀
  4. linux c做服务端使用多线程接收图片并且将图片写入数据库
  5. 每日技巧分享:虚拟直播间软件哪个好?
  6. 学生动漫网页设计模板下载你的名字 大学生HTML网页制作作品 简单漫画网页设计成品 dreamweaver学生网站模板
  7. 《帝国时代Ⅱ》图像资源查看器源代码
  8. 架构-软件工程模块-2
  9. 实验吧——密码学-变异凯撒
  10. 即时通讯安全篇(十一):IM聊天系统安全手段之传输内容端到端加密技术