zoukankan      html  css  js  c++  java
  • glibc多线程 内存不释放问题 用TCmalloc替代malloc

    TCMalloc 安装和使用

    http://blog.csdn.net/chen19870707/article/details/40301783

    http://blog.csdn.net/column/details/tcmalloclearning.html

    http://goog-perftools.sourceforge.net/doc/tcmalloc.html

    http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html

    glibc内存泄露以及TCmalloc 简单分析 

    via RaymondSQ

    http://www.cnblogs.com/raymondshiquan/archive/2011/06/25/tcmalloc_configuration_analysis.html

    最近开发一个私人程序时碰到了严重的内存问题,具体表现为:进程占用的内存会随着访问高峰不断上升,直到发生OOM被kill为止。我们使用valgrind等工具进行检查发现程序并无内存泄露,经过仔细调查我们发现时glibc的内存管理机制导致的,下次将发文对此深入解释,本文只列出核心的几个要素:
    
    1. glibc在多线程内存分配的场景下为了减少lock contention,会new出很多arena出来,每个线程都有自己默认的arena,但是内存申请时如果默认arena被占用,则round-robin到下一个arena。
    
    2. 每个arena的空间不可直接共享和互相借用,除非通过主arena释放给操作系统然后被各个辅助arena重新申请。
    
    3. glibc归还内存给OS有一个很苛刻的条件就是top chunk必须是free的,否则,即使应用程序已经释放了大片内存,glibc也不会将这些内存归还给OS。
    
    在我们的场景中常常是thread A alloc一片空间,最后由thread B free,所以这就造成各个arena之间及其不平衡,加上苛刻的内存归还条件,在整个程序运行过程中,占用内存几乎从未下降过,区别仅仅是缓慢上涨和快速上涨。
    
    由此我们实验了tcmalloc,具体介绍见:http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html
    
    安装过程见其中的INSTALL文件,下面简略说一下:
    
    1. install libunwind : git clone git://git.sv.gnu.org/libunwind.git
    
    2. download : http://google-perftools.googlecode.com/files/google-perftools-1.7.tar.gz
    
    3. ./configure --enable-frame_pointers && make && sudo make install
    
    4. sudo ldconfig
    
    5. g++ .... -ltcmalloc (link static lib)
    
    tcmalloc每个线程默认最大缓存16M空间,所以当线程多的时候其占用的空间还是非常可观的,在common.h中有几个参数是控制缓存空间的,可以做合理的修改(只可个人做实验,注意法律问题):
    
    1. 降低每个线程的缓存空间,可以修改common.h中的kMaxThreadCacheSize,比如2M
    
    2. 降低所有线程的缓存空间的总大小,可以修改common.h中的kDefaultOverallThreadCacheSize,比如20M
    
    3. 尽快将free的空间还给central list,可以将kMaxOverages改小一点,比如1
    
    还可以定期让tcmalloc归还空间给OS,
    
    #include "google/malloc_extension.h"
     
    MallocExtension::instance()->ReleaseFreeMemory();
    实验结果证明,tcmalloc分配速度的确快,而且程序不再像以前那样内存只增不减。
    
    上面Sanjay的文章已经对tcmalloc做了个大概的介绍,我看了一下tcmalloc的核心code,下面将其分配和释放的过程简单介绍一下:
    
    线程申请资源:
    
    1. 首先根据申请空间的大小从当前线程的可用内存块里面找(每个进程维护一组链表,每个链表代表一定大小的可用空间)
    
    2. 如果step 1没有找到,则到central list里面查找(central list跟线程各自维护的list结构很像,为不同的size各自维护一组可用空间列表)
    
    3. 如果step 2 central list也没有找到,则计算分配size个字节需要分配多少page(变量:class_to_pages)
    
    4. 根据pagemap查找page对应的可用的span列表,如果找到了,则直接返回span,central list会将该span切割成合适的大小放入对应的列表中,然后交给thread cache
    
    5. 如果step 4没有找到可用的span,则向OS直接申请,然后步骤同step 4。
    
    注意的是tcmalloc向系统申请空间有三种方式:sbrk,mmap,/dev/mem文件,默认是三种都try的,一种不行换另外一种。
    
    线程释放资源:
    
    1. 释放某个object
    
    2. 找到该object所在的span
    
    3. 如果该span中所有object都被释放,则释放该span到对应的可用列表,在释放的过程中,尝试将该span跟左右spans merge成更大的span
    
    4. 如果当前thread cache的free 空间大于指定预置,归还部分空间给central list
    
    5. central list也会试图通过释放可用span列表的最后几个span来将不用的空间归还给OS
    
    tcmalloc向OS申请/释放资源是以span为单位的。
    
    tcmalloc里面不少实现值得称道,比如pagesize到void*的mapping方式,添加/移除链表元素的时候利用结构体内存布局直接赋值,span/page/item的内存层次结构等,值得一看。
    View Code
  • 相关阅读:
    Windows下好用的git客户端--GitExtentions
    高分辨率下放大netbeans中的小图标
    小书匠使用手册
    win8 telnet VirtualBox中的redhat9
    win8安装新字体
    netbeans设置字体
    win7下Chrome有两个图标的解决方法
    【转】HDU-6035-Colorful Tree
    POJ1703--Find them, Catch them(种类并查集)
    KMP的妙用(利用next数组寻找字符串的循环节)
  • 原文地址:https://www.cnblogs.com/scotth/p/4285480.html
Copyright © 2011-2022 走看看