使用jemalloc来对c,c++程序进行内存管理

本文介绍如何在C/C++程序中使用jemalloc内存管理模块提升性能。通过替代libc的malloc,jemalloc能有效改善多线程环境下的内存分配效率。文章详细讲解了jemalloc的编译与使用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

本文讲述如何在c/c++程序中使用je_malloc内存管理模块来提升c/c++程序的性能。

引言

在编写c/c++服务器代码时,服务器的性能不仅决定于多线程/进程池模型的使用,还有很大程度上在于如何使用和管理内存。

目前比较流行的c/c++代码来看,nginx,memcached,mysql等都有自己的内存管理模块,而redis使用的是第三方的内存管理模块je_malloc或tc_malloc,但虽然使用的是第三方的内存管理模块redis的性能依然是不错的。

重要的是,redis支持多种数据结构,若内存的申请和释放都需要自己管理,编写的复杂度将会可想而知。

所以,若我们能够自己编写内存管理模块当然更好,但使用第三方的内存管理模块也是一个不错的选择。

jemalloc简介

jemalloc是有名的内存管理模块,可以替换libc的malloc,从而使得程序的性能得到提升。对于jemalloc的介绍这里不再说明,在baidu上一搜一大把。下面正式进入正题,讲述该内存管理模块在Linux系统下的编译和使用。

下载和编译

在网站https://github.com/jemalloc/jemalloc/releases下载最新版的jemalloc源码包。

  • 解压:
wget https://github.com/jemalloc/jemalloc/releases/download/5.2.0/jemalloc-5.2.0.tar.bz2
tar xjvf jemalloc-5.2.0.tar.bz2
cd jemalloc-5.2.0/
  • 配置
./configure --with-jemalloc-prefix=je_

注意:这一步确定要把jemalloc的函数编译成哪种形式,比如下面的配置就会把分配内存的函数编译成je_malloc的形式,把calloc编译成je_calloc等等。这样就不会和系统的libc的分配函数malloc冲突,因为若不指定该选项默认编译的分配函数是malloc。

  • 编译
make

编译完成后在lib目录下回生成以下的几个库文件:

$ ls ./lib
libjemalloc.a  libjemalloc_pic.a  libjemalloc.so  libjemalloc.so.2

其中libjemalloc.a是静态库,
libjemalloc.so.2是动态库,这里我使用的是静态库。

使用jemalloc

  • 在将要使用的工程目录下创建两个目录:
cd ../
mkdir testproject
mkdir ./testproject/lib
mkdir  ./testproject/include

并把在jemalloc库源码目录include下的jemalloc.h,jemalloc_defs.h和libjemalloc.a分别复制到include和lib目录下,并创建一下测试函数。

cp jemalloc-5.2.0/include/jemalloc/jemalloc.h ./testproject/include
cp jemalloc-5.2.0/include/jemalloc/jemalloc_defs.h ./testproject/include
cp  libjemalloc.a ./testproject/lib
cd ./testproject
  • 创建diymalloc.h 文件,内容如下:
#ifndef _DIYMALLOC_H_
#define _DIYMALLOC_H_

#include <jemalloc.h>

//define to jemalloc
#define malloc(size) je_malloc(size)
#define calloc(count,size) je_calloc(count,size)
#define realloc(ptr,size) je_realloc(ptr,size)
#define free(ptr) je_free(ptr)

#endif
  • 创建dtest.c文件,内容如下:
#include <stdio.h>
#include "diymalloc.h"

int main(void)
{
    char *pcon;

    pcon = malloc(10*sizeof(char));
    if (!pcon)
        fprintf(stderr, "malloc failed!\n");

	if (pcon != NULL) {
		free(pcon);
		pcon = NULL;
	}
    fprintf(stderr, "main end!\n");
    return 0;
}

  • 创建Makefile文件,内容如下:
CC=gcc
CFLAGS=-Wall -g
INCLUDES=-I ./include/
ALLOC_DEP=./lib/libjemalloc.a
ALLOC_LINK=$(ALLOC_DEP) -lpthread -ldl

dtest: dtest.o
    $(CC) $(INCLUDES) $(CFLAGS) -o dtest dtest.o $(ALLOC_LINK)

dtest.o: dtest.c $(ALLOC_DEP)
    $(CC) -c $(INCLUDES) $(CFLAGS) dtest.c

clean:
    rm -f dtest dtest.o
  • 编译并运行
make
./dtest

若没有任何错误,说明程序运行成功。下面,可以通过gdb来跟踪jemalloc的函数调用,从而可以分析jemalloc的具体实现。

  • 可以使用gdb进行跟踪,查看jemalloc的执行流程
 gdb ./dtest

通过gdb就可以调试jemalloc的实现代码了,具体的代码,可以自己一步一步的执行来分析。

(gdb) b main
Breakpoint 1 at 0x40174e: file dtest.c, line 8.
(gdb) r
Starting program: /diskb/testjemalloc/dtest 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at dtest.c:8
8	    pcon = malloc(10*sizeof(char));
(gdb) s
je_malloc (size=10) at src/jemalloc.c:2253
2253		if (unlikely(!tsd || !tsd_fast(tsd) || (size > SC_LOOKUP_MAXCLASS))) {
(gdb) pwd
Working directory /diskb/testjemalloc.
(gdb) n
2259		if (unlikely(ticker_trytick(&tcache->gc_ticker))) {
(gdb) n
2263		szind_t ind = sz_size2index_lookup(size);
(gdb) n
2293		void* ret = cache_bin_alloc_easy(bin, &tcache_success);
(gdb) n
2263		szind_t ind = sz_size2index_lookup(size);
(gdb) n
2266			usize = sz_index2size(ind);
(gdb) n
2293		void* ret = cache_bin_alloc_easy(bin, &tcache_success);
(gdb) n

参考资源:

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值