使用Capstone时出现大量不可释放内存的问题求助
问题:小 malloc 调用导致 Capstone 内存无法释放
我使用Capstone对/usr/lib/x86_64-linux-gnu/dri/i965_dri.so中7,838,304字节的片段进行反汇编,代码如下:
#include <stdio.h> #include <string.h> #include <stdint.h> #include <stdarg.h> #include <stdlib.h> #include <capstone/capstone.h> #define MAX_DISAS_BYTES (0x8e0bb0 - 0x167150) #define MAX_PATH_LEN 200 unsigned char code [MAX_DISAS_BYTES]; void disas() { cs_insn *insns; int count; unsigned long fileOff = 0x167150; unsigned long addrOff = 0x167150; unsigned int size = (0x8e0bb0 - 0x167150); char fileName [MAX_PATH_LEN] = "/usr/lib/x86_64-linux-gnu/dri/i965_dri.so"; if (size > (MAX_DISAS_BYTES)) { printf("fn size too large (%d > %d)\n", size , (MAX_DISAS_BYTES)); exit(1); } FILE *f = fopen(fileName, "rb"); if (!f) { printf("fopen"); exit(1); } if (fseek(f, fileOff, SEEK_SET) != 0) { printf("fseek"); fclose(f); exit(1); } size_t n = fread(code, 1, MAX_DISAS_BYTES, f); fclose(f); csh handle; if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) { fprintf(stderr, "Failed to initialize Capstone\n"); exit(1); } // Enable detailed mode cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); count = cs_disasm(handle, code, size, addrOff, 0, &insns); // bad mallocs void *m1 = malloc(sizeof(cs_detail)); void *m2 = malloc(sizeof(cs_detail)); void *m3 = malloc(sizeof(cs_detail)); void *m4 = malloc(sizeof(cs_detail)); void *m5 = malloc(sizeof(cs_detail)); // end of bad mallocs if (count > 0) { //for (size_t i = 0; i < count; i++) //{ // printf("0x%"PRIx64":\t%s\t%s\n", insns[i].address, insns[i].mnemonic, insns[i].op_str); //} printf("to free\n"); sleep(5); cs_free(insns, count); printf("freed\n"); sleep(5); } else { printf("Failed to disassemble bytes at offset 0x%lx\n", fileOff); exit(1); } cs_close(&handle); } int main() { disas(); return 0; }
问题详情
添加标记为// bad mallocs的五个malloc()调用后,大量内存变为不可释放状态:
- 程序执行前,系统RSS为2.8 GB
- 执行
printf("to free\n")时,RSS为6.28 GB - 执行
printf("freed\n")时,RSS仍有5.86 GB,近3GB内存无法释放
但移除这些malloc调用,或者在调用cs_free()前释放它们,cs_free()就能正常释放额外内存。想知道这几个小的动态分配为何会导致大量内存不可释放。
原因分析
- Capstone的内存分配特性:启用
CS_OPT_DETAIL模式后,cs_disasm会为大量指令分配详细信息内存,这类大内存通常通过glibc的mmap接口分配(属于"大块内存",一般超过128KB),释放时本可以直接归还给内核。 - glibc malloc的内存池机制:小块内存(比如
sizeof(cs_detail)这类几十到几百字节的分配)会被放入malloc的用户态内存池,不会立即归还给内核。而且如果小块内存和Capstone的大块内存处于同一段内存区域(比如同一个虚拟内存页组),glibc不会主动合并内存页并归还内核。 - 冲突点:你在
cs_disasm之后分配的小块malloc,会占用Capstone大块内存所在的部分内存页。当cs_free释放Capstone的内存时,因为这些小块内存还占用着同区域的页,内核无法回收整个大块内存区域,导致RSS居高不下。如果提前释放这些小块malloc,Capstone的大块内存区域就没有被占用,cs_free后glibc就能把整个大块归还给内核,RSS就会正常下降。
内容的提问来源于stack exchange,提问作者TheAhmad
相关产品推荐
相关产品推荐

