前言:

        本来是让同事追踪下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的测试代码

为了避免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,也可以配合着使用系统工具。


总结:

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



对Python及运维开发感兴趣的朋友可以加QQ群 : 478476595 !!!
{ 2000人qq大群内有各厂大牛,常组织线上分享及沙龙,对高性能及分布式场景感兴趣同学欢迎加入该QQ群 }

另外如果大家觉得文章对你有些作用!   帮忙点击广告. 一来能刺激我写博客的欲望,二来好维护云主机的费用.
如果想赏钱,可以用微信扫描下面的二维码. 另外再次标注博客原地址  xiaorui.cc  ……   感谢!
暂无相关产品

评论已关闭。