jemalloc安装和使用

前言

  jemalloc是一个内存分配器,最开始出现在FreeBSD上的libc中,FreeBSD最早使用phkmalloc,但它不是在多处理器系统且支持多线程的情况下设计的,为了解决多处理器系统和多线程应用程序的可扩展性瓶颈,由此诞生jemalloc,它是Jason Evans 2005年进行开发的,因此叫"je"。在2007年的时候为了改善Firefox在3.0版中的内存使用情况,使用jemalloc解决了在Windows平台上的碎片问题,同时也给jemalloc带来了许多通用的增强功能。2009年Jason Evans改进jemalloc以处理Facebook服务器通常承受的极端负载,并增加了许多支持开发和监视的功能。2017年便由一个Facebook团队进行持续的开发和维护。
  jemalloc在多处理器和多线程系统中具有很强的可扩展的并发支持,部分是通过使用多个arenas 来实现(从中进行分配原始内存块),并且以循环方式将线程分配给arenas。这意味着可以减少锁竞争,因为尽管多个线程可以并发调用malloc或free,但只有在它们共享相同的arenas时才会竞争。jemalloc强调避免碎片,它会尝试连续分配内存并且最大程度地减少内存使用总量。

由于CPU缓存,RAM和虚拟内存分页的影响,内存布局可能会对应用程序其余部分的运行速度产生重大影响。内存分配和释放并不是一个简单的问题。关于jemalloc算法的工作方式和更深入的分析请参见论文:“A Scalable Concurrent malloc(3) Implementation for FreeBSD”。


安装和测试

从jemalloc的github地址:https://github.com/jemalloc/jemalloc 下载压缩包,解压后进入目录执行安装,我的安装路径是/root/Download/jemalloc,操作如下:

unzip jemalloc-dev.zip
mv jemalloc-dev jemalloc
cd jemalloc
./autogen.sh
make -j 6
make install

安装完成之后目录下多出一些文件,和.so文件:
jemalloc1
对于以下ex_stats_print.c示例代码:

#include <stdlib.h>
#include <jemalloc/jemalloc.h>

void do_something(size_t i) {
        // Leak some memory.
        malloc(i * 100);
}

int main(int argc, char **argv) {
        for (size_t i = 0; i < 1000; i++) {
                do_something(i);
        }

        // Dump allocator statistics to stderr.
        malloc_stats_print(NULL, NULL, NULL);

        return 0;
}

使用以下命令编译:

gcc ex_stats_print.c  -o ex_stats_print.out -L/root/Download/jemalloc/lib -ljemalloc

编译成功之后执行文件./ex_stats_print.out报找不到.so.2文件的错误:./ex_stats_print.out: error while loading shared libraries: libjemalloc.so.2: cannot open shared object file: No such file or directory。这个错误解决在我之前的博客关于benchmark的Instruction Cache Misses测试中“常见错误及解决办法”里面有说到。
在此可采用以下命令解决:

echo /root/Download/jemalloc/lib >> /etc/ld.so.conf   
ldconfig

再次执行./ex_stats_print.out将得到以下结果:
jemalloc2


1. 用例

以下用例内容来自jemalloc wiki:https://github.com/jemalloc/jemalloc/wiki/Use-Case

  1. 查找内存损坏错误
  • 从jemalloc 5.0开始,已删除与valgrind的集成。如果jemalloc是用--enable-debug指定配置的,则将编译各种断言以检测双精度释放,未对齐的指针等。这些检查对于正确运行应用程序不是必需的,但在开发过程中可能会有所帮助。禁用线程缓存(MALLOC_CONF=tcache:false)往往会使jemalloc的内部断言在捕获应用程序错误(尤其是两次释放)时更加有效。
  • 如果jemalloc是使用--enable-fill指定的配置的,则可以使用MALLOC_CONF=junk:true在环境中进行设置,以告知malloc()用0xa5字节填充对象,并用free()释放内存。
  1. 基本分配器统计
    默认情况下,jemalloc使用线程本地存储进行对象缓存。对于前面使用的ex_stats_print.c示例代码,运行MALLOC_CONF=stats_print:true ./ex_stats_print.out就能知道jemalloc在内部实际响应应用程序的内存分配活动在做什么,以改进分配器。

  2. 使用mallctl*()自我检查
    对于以下ex_mallctl.c示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <jemalloc/jemalloc.h>

void do_something(size_t i)
{
        // Leak some memory.
        malloc(i * 100);
}

int main(int argc, char **argv)
{
        size_t i, sz;

        for (i = 0; i < 100; i++) {
                do_something(i);

                // Update the statistics cached by mallctl.
                uint64_t epoch = 1;
                sz = sizeof(epoch);
                mallctl("epoch", &epoch, &sz, &epoch, sz);

                // Get basic allocation statistics.  Take care to check for
                // errors, since --enable-stats must have been specified at
                // build time for these statistics to be available.
                size_t sz, allocated, active, metadata, resident, mapped;
                sz = sizeof(size_t);
                if (mallctl("stats.allocated", &allocated, &sz, NULL, 0) == 0
                    && mallctl("stats.active", &active, &sz, NULL, 0) == 0
                    && mallctl("stats.metadata", &metadata, &sz, NULL, 0) == 0
                    && mallctl("stats.resident", &resident, &sz, NULL, 0) == 0
                    && mallctl("stats.mapped", &mapped, &sz, NULL, 0) == 0) {
                        fprintf(stderr,
                            "Current allocated/active/metadata/resident/mapped: %zu/%zu/%zu/%zu/%zu\n",
                            allocated, active, metadata, resident, mapped);
                }
        }
        return (0);
}

执行以下命令进行编译运行得到结果如下:

gcc ex_mallctl.c -o ex_mallctl.out -L/root/Download/jemalloc/lib -ljemalloc
Current allocated/active/metadata/resident/mapped: 111400/122880/2854856/2953216/6414336
Current allocated/active/metadata/resident/mapped: 122600/151552/2854984/2981888/6443008
Current allocated/active/metadata/resident/mapped: 145000/180224/2855112/3014656/6471680
Current allocated/active/metadata/resident/mapped: 165480/200704/2855240/3035136/6492160
Current allocated/active/metadata/resident/mapped: 194152/229376/2855368/3063808/6520832
Current allocated/active/metadata/resident/mapped: 199272/237568/2855624/3072000/6529024
Current allocated/active/metadata/resident/mapped: 219752/258048/2855752/3092480/6549504
Current allocated/active/metadata/resident/mapped: 232040/270336/2855880/3104768/6561792
....
  1. 泄漏检查
    jemalloc的堆配置文件可以帮助检测应用程序中是否发现内存泄漏。jemalloc的堆配置文件输出文件是gperftools创建的文件的功能超集,关于gperftools堆配置文件的使用在:https://github.com/gperftools/gperftools/,这里不做安装和使用说明。
    使用如下命令来查看程序退出时分配了什么内存:
MALLOC_CONF=prof_leak:true,lg_prof_sample:0,prof_final:true LD_PRELOAD=/root/Download/jemalloc/lib/libjemalloc.so.2 w

得到类似以下输出:

<jemalloc>: ......
<jemalloc>: ......
<jemalloc>: ......
 15:31:15 up  3:05,  1 user,  load average: 0.14, 0.41, 0.37
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     tty7     :0               12:27    3:05m  7:04   7:04  /usr/lib/xorg/Xorg :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch

要生成发生泄漏的调用图的PDF,请运行:

jeprof --show_bytes --pdf `which w` jeprof.19678.0.f.heap > w.pdf
  1. 堆分析
    除了以上能在出口进行泄漏检查外,jemalloc还能转储配置文件。转储到指定的文件名,MALLOC_CONF中将prof设置为true:
export MALLOC_CONF="prof:true,prof_prefix:jeprof.out"

对于以下prof.c示例代码,编译运行之后便能看到结果:

#include <stdio.h>
#include <jemalloc/jemalloc.h>
int main()
{
     const char *fileName = "heap_info.out";
     mallctl("prof.dump", NULL, NULL, &fileName, sizeof(const char *));
     return 0;
}

在benchmark中使用

在numa架构的服务器中使用SPEC CPU测试benchmark时,在配置文件中都会使用到jemalloc。关于服务器NUMA nodes相关信息可使用以下命令查看:

numactl --hardware
head /proc/cpuinfo

在config文件中,以aocc2.0 speed cfg文件为例

...
EXTRA_PORTABILITY = -DSPEC_LP64 
EXTRA_LIBS = -lamdlibm -lm  -L/home/zgl/cpu2017/jemalloc/lib/64 -ljemalloc #-fopenmp=libomp -lomp 
MATHLIBOPT = -lamdlibm
...
EXTRA_LIBS = -lpthread -ldl -lmvec -lamdlibm -L/home/zgl/cpu2017/jemalloc/lib/64 -ljemalloc

References:

  • https://github.com/jemalloc/jemalloc/wiki/Background
原创文章 38 获赞 13 访问量 4013

猜你喜欢

转载自blog.csdn.net/qq_36287943/article/details/105491301