요새 Redis Issue를 보면 메모리를 쓰고 나도 계속 mem_fragmentation_ratio 와 used_memory_rss 값이 여전히 높다라는 글이 자주 올라옵니다. 실제로 제목은 mem_fragmentation_ratio 를 구하는 방법이지만, mem_fragmentation_ratio 는 다음과 같이 간단하게 구해집니다.(Info Command를 통해서 redis에서 확인가능합니다.)
mem_fragmentation_ratio = used_memory_rss / zmalloc_used_memory
코드를 보면 다음과 같습니다.
/* Fragmentation = RSS / allocated-bytes */ float zmalloc_get_fragmentation_ratio(void) { return (float)zmalloc_get_rss()/zmalloc_used_memory(); }
그렇다면 사실 핵심은 zmalloc_get_rss를 어떻게 구하는가가 핵심이라는 걸 알게됩니다.
rss 값을 구하는 것은 여러가지 정책이 있는데 proc 를 제공해주는 곳에서는 /proc/{pid}/stat 값을 읽어서 해당 값을 알 수 있습니다. 24번째 값이 RSS 의 페이지 개수입니다. TASK_INFO를 제공해주는 곳에서는 해당 함수를 이용해서 rss 값을 구하고, 이도 저도 없는 플랫폼은 그냥 zmalloc_used_memory를 리턴합니다.(이때는 무조건 ratio 가 1이 되겠죠?)
코드는 zmalloc.c에 존재하고 리눅스에서 proc를 읽어서 처리하는 것은 다음과 같습니다. 코드는 워낙 간단해서 다른 설명은 없습니다. 핵심은 rss 값을 읽어오는 것과, sysconf 를 PAGESIZE를 가져옵니다. rss 가 페이지 개수이므로 여기에 PAGESIZE를 곱하면 실제 사용하고 있는 총 메모리 양이 나옵니다.(OS가 페이지 단위로 메모리를 할당하므로 ㅎㅎㅎ 이게 실제 사용량이 됩니다.)
size_t zmalloc_get_rss(void) { int page = sysconf(_SC_PAGESIZE); size_t rss; char buf[4096]; char filename[256]; int fd, count; char *p, *x; snprintf(filename,256,"/proc/%d/stat",getpid()); if ((fd = open(filename,O_RDONLY)) == -1) return 0; if (read(fd,buf,4096) <= 0) { close(fd); return 0; } close(fd); p = buf; count = 23; /* RSS is the 24th field in /proc/<pid>/stat */ while(p && count--) { p = strchr(p,' '); if (p) p++; } if (!p) return 0; x = strchr(p,' '); if (!x) return 0; *x = '\0'; rss = strtoll(p,NULL,10); rss *= page; return rss; }
/proc/{pid}/stat 의 정보는 다음 페이지를 보시면 됩니다.