strace分析追踪malloc申请内存过程

前言:

        本来是让同事追踪下select超时调用频率,结果同事反问我线上的一个服务为什么会频繁的调用mmap系统调用? 考虑到应该还有不少人想听听这个,所以写了这篇关于如何使用strace分析malloc内存申请过程。长话短说,申请内存空间一般就两种方法,一种是malloc,另一种是 mmap映射空间。 在使用malloc()分配内存的时候,可能系统调用brk(),也可能调用mmap()。

malloc的调用规律?

1. 即分配一块小型内存(小于或等于128kb),malloc()会调用brk()调高断点(brk是将数据段(.data)的最高地址指针_edata往高地址推),分配的内存在堆区域。

2. 当分配一块大型内存(大于128kb),malloc()会调用mmap2()分配一块内存(mmap是在进程的虚拟地址空间中(一般是堆和栈中间)找一块空闲的空间。

该文章后续仍在不断的更新修改中, 请移步到原文地址 http://xiaorui.cc/?p=5334

malloc简约流程图

为了更直观的理解申请内存内存过程直接画个图吧,这样相对也好理解。

知识的海洋太tm深了,深度差不多就可以了,所以我这里不再详细的追究mmap和brk的实现原理。太底层的实现估计也没多少人去看吧。 另外,全网关于malloc的博客,很多也是抄来抄去的。有兴趣大家可以自己搜一把。

下面我们拿着Python和golang为例,从strace的角色来跟踪下malloc的过程。malloc是glibc的库,strace追到的syscall当然不是malloc字眼,上面有说过,要么brk,要么mmap . 


python的测试代码

# coding:utf-8
# xiaorui.cc

import time

s = '''

man7.org > Linux > man-pages

Linux/UNIX system programming training

NAME | SYNOPSIS | DESCRIPTION | OPTIONS | FILTER SPECIFICATIONS | FILTER EXPRESSIONS | PROTOTYPE LIBRARY DISCOVERY | BUGS | FILES | AUTHOR | SEE ALSO | COLOPHON


LTRACE(1)                       User Commands                      LTRACE(1)
NAME         top
       ltrace - A library call tracer
SYNOPSIS         top
       ltrace [-e filter|-L] [-l|--library=library_pattern] [-x filter] [-S]
       [-b|--no-signals] [-i] [-w|--where=nr] [-r|-t|-tt|-ttt] [-T]
       [[-F|--config] pathlist] [-A maxelts] [-s strsize] [-C|--demangle]
       [-a|--align column] [-n|--indent nr] [-o|--output filename]
       [-D|--debug mask] [-u username] [-f] [-p pid] [[--] command [arg
       ...]]

       ltrace -c [-e filter|-L] [-l|--library=library_pattern] [-x filter]
       [-S] [-o|--output filename] [-f] [-p pid] [[--] command [arg ...]]
'''

l = []
a = ""

while 1:
    a = a + s
    print len(a)
    l.append(a)
    time.sleep(0.1)

为了避免python内存池和intern缓存对象池的影响,所以我们的测试脚本不断的创建新变量放到一个全局列表里面。 这样就可以实现不断的申请新内存。

下面是strace后的截图,我们可以清晰的看到当申请的内存空间小于128kb的时候,调用malloc的brk syscall,  大于等于128kb就调用mmap 。

golang的内存池构建了mcache, mcentral, mheap数据结构,当mheap也没有可用内存才会向mmap申请。我们通过strace可以明显的看到。看了下golang申请内存的源码,只能看到mmap,没找到malloc相关的调用。

strace追踪malloc平时怎么用?

记得去年用python写了一个数据合并服务,该服务会不断的从redis里取数据,输出到hbase里。由于没有控制好边界条件,最后占用了很多内存被系统给oom了.   因为该问题好重现,所以在线边跑边strace, 通过strace看到某个线程每次redis zrange的时候,会疯狂的brk和mmap申请内存。 问题显而易见,zrange的数据太多了… 

平时遇到bug,不要一味的使用代码层的bug,也可以配合着使用系统工具。


总结:

       当你浮躁了,可以多关注下操作系统的本源,各个语言的原理实现,对自己还是有提升的。


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc