内存探测组件,预留热插拔。

This commit is contained in:
1iaan
2026-01-26 13:07:10 +00:00
parent 9e757ece87
commit c99867b342
9 changed files with 187 additions and 37 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@
kvstore kvstore
testcase testcase
mem_leak

View File

@@ -9,8 +9,8 @@ COMMON_SRCS = ./common/config.c ./diskuring/diskuring.c
SRCS = $(NET_SRCS) $(KV_SRCS) $(MEM_SRCS) $(COMMON_SRCS) SRCS = $(NET_SRCS) $(KV_SRCS) $(MEM_SRCS) $(COMMON_SRCS)
INC = -I./NtyCo/core/ -I/usr/include/libxml2 INC = -I./NtyCo/core/ -I/usr/include/libxml2 -I./
LIBDIRS = -L./NtyCo/ -L./memory/ -L./diskuring/ LIBDIRS = -L./NtyCo/
LIBS = -lntyco -lpthread -luring -ldl -lxml2 -ljemalloc LIBS = -lntyco -lpthread -luring -ldl -lxml2 -ljemalloc
TARGET = kvstore TARGET = kvstore
@@ -33,7 +33,7 @@ ECHO:
@echo $(SUBDIR) @echo $(SUBDIR)
$(TARGET): $(OBJS) $(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LIBDIRS) $(LIBS) $(CC) $(CFLAGS) -o $@ $^ $(LIBDIRS) $(LIBS)
$(TEST_REDIS): $(TEST_REDIS_SRCS) $(TEST_REDIS): $(TEST_REDIS_SRCS)
$(CC) -g -o $@ $^ $(TEST_REDIS_LDFLAGS) $(CC) -g -o $@ $^ $(TEST_REDIS_LDFLAGS)
@@ -41,7 +41,8 @@ $(TEST_REDIS): $(TEST_REDIS_SRCS)
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) $(INC) -c $^ -g -o $@ $(CC) $(CFLAGS) $(INC) -c $^ -g -o $@
clean: clean: clmem
rm -rf $(OBJS) $(TARGET) $(TEST_REDIS) rm -rf $(OBJS) $(TARGET) $(TEST_REDIS)
clmem:
rm -rf mem_leak/*

View File

@@ -57,6 +57,7 @@ static void set_default_config(AppConfig *cfg)
cfg->master_port = 8888; cfg->master_port = 8888;
cfg->persistence = PERSIST_NONE; cfg->persistence = PERSIST_NONE;
cfg->allocator = ALLOC_JEMALLOC; cfg->allocator = ALLOC_JEMALLOC;
cfg->leak_mode = MEMLEAK_DETECT_OFF;
} }
/* ---- 字符串转枚举 ---- */ /* ---- 字符串转枚举 ---- */
@@ -90,9 +91,18 @@ static void parse_allocator(const char *s, AllocatorType *out)
if (!s || !out) return; if (!s || !out) return;
if (!strcasecmp(s, "jemalloc")) *out = ALLOC_JEMALLOC; if (!strcasecmp(s, "jemalloc")) *out = ALLOC_JEMALLOC;
else if (!strcasecmp(s, "malloc")) *out = ALLOC_MALLOC; else if (!strcasecmp(s, "malloc")) *out = ALLOC_MALLOC;
else if (!strcasecmp(s, "mypool")) *out = ALLOC_MYPOOL;
else *out = ALLOC_OTHER; else *out = ALLOC_OTHER;
} }
static void parse_leakage(const char *s, MemLeakDetectMode *out)
{
if (!s || !out) return;
if (!strcasecmp(s, "enable")) *out = MEMLEAK_DETECT_ON;
else if (!strcasecmp(s, "disable")) *out = MEMLEAK_DETECT_OFF;
else *out = MEMLEAK_DETECT_OFF;
}
static int read_file_mmap(const char *filename, void **out_addr, size_t *out_len, int *out_fd) { static int read_file_mmap(const char *filename, void **out_addr, size_t *out_len, int *out_fd) {
if (!filename || !out_addr || !out_len || !out_fd) return -1; if (!filename || !out_addr || !out_len || !out_fd) return -1;
@@ -174,11 +184,21 @@ const char *allocator_to_string(AllocatorType a)
switch (a) { switch (a) {
case ALLOC_JEMALLOC: return "jemalloc"; case ALLOC_JEMALLOC: return "jemalloc";
case ALLOC_MALLOC: return "malloc"; case ALLOC_MALLOC: return "malloc";
case ALLOC_MYPOOL: return "mypool";
case ALLOC_OTHER: return "other"; case ALLOC_OTHER: return "other";
default: return "unknown"; default: return "unknown";
} }
} }
const char *leakage_to_string(MemLeakDetectMode a)
{
switch (a) {
case MEMLEAK_DETECT_ON: return "enable";
case MEMLEAK_DETECT_OFF: return "disable";
default: return "unknown";
}
}
/* ---- 主函数:从 XML 加载配置 ---- */ /* ---- 主函数:从 XML 加载配置 ---- */
/* server 部分 */ /* server 部分 */
@@ -333,6 +353,15 @@ void memory_load(xmlNodePtr *root, AppConfig *out_cfg){
xmlFree(txt); xmlFree(txt);
} }
} }
xmlNodePtr leakage_node = find_child(mem, "leakage");
if (leakage_node) {
xmlChar *txt = xmlNodeGetContent(leakage_node);
if (txt) {
parse_leakage((char *)txt, &out_cfg->leak_mode);
xmlFree(txt);
}
}
} }
} }

View File

@@ -2,6 +2,7 @@
#define __CONFIG_H__ #define __CONFIG_H__
#include <stddef.h> #include <stddef.h>
#include <memory/alloc_dispatch.h>
typedef enum { typedef enum {
LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG,
@@ -19,11 +20,17 @@ typedef enum {
PERSIST_NONE PERSIST_NONE
} PersistenceType; } PersistenceType;
typedef enum { // typedef enum {
ALLOC_JEMALLOC, // ALLOC_JEMALLOC,
ALLOC_MALLOC, // ALLOC_MALLOC,
ALLOC_OTHER // ALLOC_MYPOOL,
} AllocatorType; // ALLOC_OTHER
// } AllocatorType;
// typedef enum {
// MEMLEAK_DETECT_OFF = 0, // 关闭检测
// MEMLEAK_DETECT_ON = 1 // 开启检测
// } MemLeakDetectMode;
typedef struct { typedef struct {
char ip[64]; char ip[64];
@@ -43,6 +50,7 @@ typedef struct {
char hash_file[256]; char hash_file[256];
AllocatorType allocator; AllocatorType allocator;
MemLeakDetectMode leak_mode;
} AppConfig; } AppConfig;
/** /**
@@ -55,5 +63,6 @@ const char *log_level_to_string(LogLevel lvl);
const char *server_mode_to_string(ServerMode mode); const char *server_mode_to_string(ServerMode mode);
const char *persistence_to_string(PersistenceType p); const char *persistence_to_string(PersistenceType p);
const char *allocator_to_string(AllocatorType a); const char *allocator_to_string(AllocatorType a);
const char *leakage_to_string(MemLeakDetectMode a);
#endif /* CONFIG_H */ #endif /* CONFIG_H */

View File

@@ -27,6 +27,7 @@
</persistence> </persistence>
<memory> <memory>
<allocator>jemalloc</allocator> <!-- jemalloc / malloc / other --> <allocator>mypool</allocator> <!-- jemalloc / malloc / mypool -->
<leakage>enable</leakage> <!-- enable/disable-->
</memory> </memory>
</config> </config>

View File

@@ -1,5 +1,5 @@
#include "diskuring.h" #include "diskuring.h"
#include "../memory/alloc_dispatch.h" #include "memory/alloc_dispatch.h"
#include <poll.h> #include <poll.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>

View File

@@ -353,6 +353,7 @@ int init_kvengine(void) {
kvs_replay_log(global_cmd_log_fd); kvs_replay_log(global_cmd_log_fd);
} }
printf("kvengine init complete\n");
return 0; return 0;
} }
@@ -370,10 +371,14 @@ void dest_kvengine(void) {
destroy_cmd_log(global_cmd_log_fd); destroy_cmd_log(global_cmd_log_fd);
} }
void init_memory_pool(void){ void init_memory_pool(AppConfig *cfg){
#if MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC #if MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
mp_create(&global_mempool); mp_create(&global_mempool);
#endif #endif
kvs_set_memleak_detect(cfg->leak_mode);
kvs_set_alloc_type(cfg->allocator);
printf("mempool init complete\n");
} }
void dest_memory_pool(void){ void dest_memory_pool(void){
@@ -440,7 +445,9 @@ int init_config(AppConfig *cfg){
printf("|—— Persist-hash : %s\n", cfg->hash_file); printf("|—— Persist-hash : %s\n", cfg->hash_file);
printf("Log level : %s\n", log_level_to_string(cfg->log_level)); printf("Log level : %s\n", log_level_to_string(cfg->log_level));
printf("Allocator : %s\n", allocator_to_string(cfg->allocator)); printf("Memory : \n");
printf("|——Allocator : %s\n", allocator_to_string(cfg->allocator));
printf("|——MemLeakDetectMode : %s\n", leakage_to_string(cfg->leak_mode));
printf("=============== Config ===============\n"); printf("=============== Config ===============\n");
xmlCleanupParser(); xmlCleanupParser();
@@ -476,9 +483,8 @@ int main(int argc, char *argv[]) {
init_memory_pool(); init_memory_pool(&global_cfg);
init_kvengine(); init_kvengine();
#if (NETWORK_SELECT == NETWORK_REACTOR) #if (NETWORK_SELECT == NETWORK_REACTOR)
reactor_start(port, kvs_protocol, master_ip, master_port); // reactor_start(port, kvs_protocol, master_ip, master_port); //

View File

@@ -1,30 +1,111 @@
#include "alloc_dispatch.h"
#include "mempool.h" #include "mempool.h"
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include <stdatomic.h>
#include <jemalloc/jemalloc.h> #include <jemalloc/jemalloc.h>
mp_pool_t global_mempool; mp_pool_t global_mempool;
void *kvs_malloc(size_t size) { static atomic_int g_memory_mode = ATOMIC_VAR_INIT(MEMLEAK_DETECT_OFF);
#if MEMORY_SELECT_MALLOC == MEMORY_USE_DEFAULT static atomic_int g_memleak_detect_mode = ATOMIC_VAR_INIT(MEMLEAK_DETECT_OFF);
return malloc(size);
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC // 设置内存池类型
return mp_alloc(size); void kvs_set_alloc_type(AllocatorType mode) {
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_JEMALLOC atomic_store(&g_memory_mode, mode);
return je_malloc(size);
#endif
} }
void kvs_free(void *ptr) { // 获取当前内存池类型
#if MEMORY_SELECT_MALLOC == MEMORY_USE_DEFAULT AllocatorType kvs_get_alloc_type(void) {
free(ptr); return atomic_load(&g_memory_mode);
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC }
int ret = mp_free(ptr);
if(ret == MEMPOOL_DOUBLE_FREE){ // 设置内存泄漏检测模式
printf("double free %p\n", ptr); void kvs_set_memleak_detect(MemLeakDetectMode mode) {
atomic_store(&g_memleak_detect_mode, mode);
}
// 获取当前内存泄漏检测模式
MemLeakDetectMode kvs_get_memleak_detect(void) {
return atomic_load(&g_memleak_detect_mode);
}
void *kvs_malloc_impl(size_t size){
switch (atomic_load(&g_memleak_detect_mode)){
case ALLOC_MALLOC:
return malloc(size);
case ALLOC_MYPOOL:
return mp_alloc(&global_mempool, size);
case ALLOC_JEMALLOC:
return je_malloc(size);
case ALLOC_OTHER:
default:
return malloc(size);
} }
#elif MEMORY_SELECT_MALLOC == MEMORY_USE_JEMALLOC return NULL;
je_free(ptr); }
#endif
void kvs_free_impl(void *ptr) {
switch (atomic_load(&g_memleak_detect_mode)){
case ALLOC_MALLOC:
free(ptr);
break;
case ALLOC_MYPOOL:{
int ret = mp_free(&global_mempool, ptr);
if(ret == MEMPOOL_DOUBLE_FREE){
printf("double free %p\n", ptr);
}
break;
}
case ALLOC_JEMALLOC:
je_free(ptr);
break;
case ALLOC_OTHER:
default:
free(ptr);
break;
}
}
void *nMalloc(size_t size, const char * filename, const char *func, int line){
void *ptr = kvs_malloc_impl(size);
if(atomic_load(&g_memleak_detect_mode) == MEMLEAK_DETECT_ON) {
char buff[128];
snprintf(buff, 128, "./mem_leak/%p.mem", ptr);
FILE* fp = fopen(buff, "w");
if(!fp){
kvs_free(ptr);
return NULL;
}
fprintf(fp, "[+] [%s : %s : %d] %p: %ld malloc\n", filename, func, line, ptr, size);
fflush(fp);
fclose(fp);
}
return ptr;
}
void nFree(void *ptr, const char * filename, const char *func, int line){
if(!ptr) {
return ;
}
if(atomic_load(&g_memleak_detect_mode) == MEMLEAK_DETECT_ON) {
char buff[128];
snprintf(buff, 128, "./mem_leak/%p.mem", ptr);
if(unlink(buff) < 0) {
return ;
}
}
kvs_free_impl(ptr);
} }

View File

@@ -5,14 +5,36 @@
#define MEMORY_USE_MYMALLOC 1 #define MEMORY_USE_MYMALLOC 1
#define MEMORY_USE_JEMALLOC 2 #define MEMORY_USE_JEMALLOC 2
#define MEMORY_SELECT_MALLOC MEMORY_USE_MYMALLOC
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdatomic.h>
#include "mempool.h" #include "mempool.h"
void *kvs_malloc(size_t size); typedef enum {
void kvs_free(void *ptr); ALLOC_JEMALLOC,
ALLOC_MALLOC,
ALLOC_MYPOOL,
ALLOC_OTHER
} AllocatorType;
void kvs_set_alloc_type(AllocatorType mode);
AllocatorType kvs_get_alloc_type(void);
typedef enum {
MEMLEAK_DETECT_OFF = 0, // 关闭检测
MEMLEAK_DETECT_ON = 1 // 开启检测
} MemLeakDetectMode;
void kvs_set_memleak_detect(MemLeakDetectMode mode);
MemLeakDetectMode kvs_get_memleak_detect(void);
void *kvs_malloc_impl(size_t size);
void kvs_free_impl(void *ptr);
void *nMalloc(size_t size, const char * filename, const char *func, int line);
void nFree(void *ptr, const char * filename, const char *func, int line);
#define kvs_malloc(size) nMalloc (size , __FILE__, __func__, __LINE__)
#define kvs_free(ptr) nFree (ptr , __FILE__, __func__, __LINE__)
#endif #endif