작은 block의 메모리 반복 할당/해제시 heap 이 안줄어들어요 ㅜㅜ

dao_3651의 이미지

환경 : OS : CentOS Linux release 7.1.1503 (64bit/순정),
gcc : version 4.8.5 20150623 (Red Hat 4.8.5-11)
glibc : version 2.17 (glibc-2.17-157.el7_3.1.x86_64)

유지보수 하는 시스템에 메모리 이슈가 있어 분석을 하였는데 이상한 동작을 하나 발견 하였습니다.

다음 소스코드는 SZ_BLOCK 만큼 메모리를 100만번 정도 반복 할당 후 일괄적으로 해제 하는 코드인데 SZ_BLOCK 가 120 이하일때와 이상일때 free이후 집계되는 메모리 총량에 차이가 있습니다.

121byte 부터는 정상적으로 해제가 되나
120byte 까지는 heap이 안줄어들고 있네요??

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h> 
 
#define TRY_CNT     1024 * 1000 * 1    /* number of malloc call     */
#define SZ_BLOCK    120
 
static int parseLine(char* line);
static uint64_t get_heap_memory_usage();
 
int main(int argc, char * argv[]){
 
    int i;
    int n_call_free;
    char * all_ptrs[TRY_CNT] = {NULL,};
    int total_alloc;
    int n_size_block;
    double szHeap;
 
    n_size_block = SZ_BLOCK;
    for(i=0;i<TRY_CNT;i++) {   
        all_ptrs[i] = (char *)malloc(n_size_block);
        memset(all_ptrs[i], 0x00, n_size_block);
    }
    szHeap      = (double)get_heap_memory_usage() / (1024.0 * 1024.0);
    total_alloc = n_size_block * (TRY_CNT);
    printf("malloc end : n_size_block=%d, nAlloc=%d, total_alloc=%d, now_memory=%0.2fMB\n", n_size_block, TRY_CNT, total_alloc, szHeap);
 
    for(i=0, n_call_free=0;i<TRY_CNT;i++) {
        n_call_free++;
        free(all_ptrs[i]);
    }
    szHeap = (double)get_heap_memory_usage() / (1024.0 * 1024.0);
    printf("free end   : nFree=%d now_memory=%0.2fMB\n", n_call_free, szHeap);
 
    return 0;
}
 
static int parseLine(char* line){
    int i = strlen(line);
    while (*line < '0' || *line > '9') line++;
    line[i-3] = '\0';
    i = atoi(line);
    return i;
}
 
static uint64_t get_heap_memory_usage()
{
    FILE* file = fopen("/proc/self/status", "r");
    int result = -1;
    char line[128];
 
    while (fgets(line, 128, file) != NULL){
        if (strncmp(line, "VmData:", 7) == 0){
            result = parseLine(line);
            break;
        }
    }
    fclose(file);
    return result * 1024;
}

실행 해보면 다음과 같이 120byte 단위로 할당 할 경우 free이후에도 heap size가 줄어들지 않았지만 121byte 이상을 할당 하면 free 이후 heap크기가 원복 되었습니다.

[120byte alloc]
malloc end : n_size_block=120, nAlloc=1024000, total_alloc=122880000, now_memory=125.30MB
free end : nFree=1024000 now_memory=125.30MB

[121byte alloc]
malloc end : n_size_block=121, nAlloc=1024000, total_alloc=123904000, now_memory=140.90MB
free end : nFree=1024000 now_memory=0.39MB

유지보수 하는 시스템 메모리 이슈가 있어 분석하다보니 여기까지 왔는데.. 단편화 이슈라고 생각 되기는 하는데 이해할수가 없네요 ㅠㅠ
malloc을 해도 glibc 내부에서 heap을 관리를 하니.. 어떻게 되는지 분석이 안되네요 ㅠㅠ

jick의 이미지

딱히 문제는 없는 것 같은데요. C 라이브러리에서 malloc/free를 할 때마다 OS 시스템콜을 불러서 메모리를 할당/해제하면 대단한 오버헤드가 생기기 때문에, free를 한다고 당장 그 메모리가 날아가지는 않고 free memory pool에 쌓아뒀다가 나중에 적당한 조건을 만족하면 (free pool의 사이즈가 미리 정해진 한계를 넘어간다든지) 그때 OS를 부르게 됩니다.

실행결과만 봐서는 121바이트씩 할당할 때는 그 한계를 살짝 넘어가고 120바이트씩 백만번 할당하면 그 한계 바로 밑인 것이 아닌가 싶습니다.

더 확실히 알고 싶으면 120바이트인 상태에서 TRY_CNT를 몇 배로 올려서 어떻게 되나 보시죠.

dao_3651의 이미지

glibc의 메모리 할당자가 문제였습니다.

http://small-dbtalk.blogspot.com/2013/09/jemalloc-vs-ptmalloc2.html

다음 자료처럼 메모리 할당자를 TCMalloc 으로 바꾸니 해결되네요..

많은 malloc/free가 발생 하는 시스템에서는 기본 메모리 관리자로는 fragmentation에 의해서 비효율적인 메모리 관리가 일어나는것같습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.