memory indexing differences

for 구문 사용시, 인덱싱하는 order 에 따라, 실행시간에 차이가 발생한다는 글을 보았다(참조: http://process3.blog.me/20030421397)

정말로 그럴까? 한번 확인해 보았다. 결론은? 확실한 차이가 있었다.

이유를 확인해보니, 메모리 캐시와 관련된 내용이었다.

 

— Program 1
#include <stdio.h>
#define MAX_CNT 100
int main(int argc, char** argv)
{
    int i, j, k;
    int test_data[MAX_CNT][MAX_CNT][MAX_CNT];
    for(i = 0; i < MAX_CNT; i++)
    {
        for(j = 0; j < MAX_CNT; j++)
        {
            for(k = 0; k < MAX_CNT; k++)
            {
                test_data[i][j][k] = 100;
            }
        }
    }
    return 0;
}
Result
$ time ./main
real    0m0.008s
user    0m0.004s
sys     0m0.004s
— Program 2
#include <stdio.h>
#define MAX_CNT 100
int main(int argc, char** argv)
{
    int i, j, k;
    int test_data[MAX_CNT][MAX_CNT][MAX_CNT];
    for(i = 0; i < MAX_CNT; i++)
    {
        for(j = 0; j < MAX_CNT; j++)
        {
            for(k = 0; k < MAX_CNT; k++)
            {
                test_data[k][j][i] = 100;
            }
        }
    }
    return 0;
}
$ time ./main
real    0m0.017s
user    0m0.013s

sys     0m0.004s

 

힙 영역 사용시, 보다 더 큰 차이를 확인할 수 있다.

— Program 1
#include <stdio.h>
#include <stdlib.h>
#define MAX_CNT 500
int main(int argc, char** argv)
{
    int i, j, k;
//    int test_data[MAX_CNT][MAX_CNT][MAX_CNT];
    int*** test_data;
    test_data = calloc(MAX_CNT, sizeof(int**));
    for(i = 0; i < MAX_CNT; i++)
    {
        test_data[i] = calloc(MAX_CNT, sizeof(int*));
        for(j = 0; j < MAX_CNT; j++)
        {
            test_data[i][j] = calloc(MAX_CNT, sizeof(int));
        }
    }
    for(i = 0; i < MAX_CNT; i++)
    {
        for(j = 0; j < MAX_CNT; j++)
        {
            for(k = 0; k < MAX_CNT; k++)
            {
                test_data[i][j][k] = 100;
            }
        }
    }
    return 0;
}
Result
$ time ./main
real    0m0.539s
user    0m0.367s
sys     0m0.172s
— Program 2
#include <stdio.h>
#include <stdlib.h>
#define MAX_CNT 500
int main(int argc, char** argv)
{
    int i, j, k;
//    int test_data[MAX_CNT][MAX_CNT][MAX_CNT];
    int*** test_data;
    test_data = calloc(MAX_CNT, sizeof(int**));
    for(i = 0; i < MAX_CNT; i++)
    {
        test_data[i] = calloc(MAX_CNT, sizeof(int*));
        for(j = 0; j < MAX_CNT; j++)
        {
            test_data[i][j] = calloc(MAX_CNT, sizeof(int));
        }
    }
    for(i = 0; i < MAX_CNT; i++)
    {
        for(j = 0; j < MAX_CNT; j++)
        {
            for(k = 0; k < MAX_CNT; k++)
            {
                test_data[k][j][i] = 100;
            }
        }
    }
    return 0;
}
Result
$ time ./main
real    0m5.344s
user    0m5.202s
sys     0m0.147s

utime

utime 은 파일의 Access time 및 Modification time 을 변경할 때 사용하는 함수이다.

특정 파일 정렬을 할 때, 파일의 이름을 파싱해서 정렬을 하는 것이 아닌, 파일의 Modification time 을 기준으로 정렬을 해야하는 경우가 있다.
이런 경우, 파일 작업 이후에도 이전의 Modification time 을 유지해야 하는 경우가 있는데,

이런 경우, utime 을 사용하면 편리하다.

 

utime 은 input 인자로 utimebuf 라는 구조체를 사용한다. utime 을 이용하면 access time 과 modification time 을 수정할 수 있다.

struct utimbuf {
    time_t actime;       /* access time */
    time_t modtime;      /* modification time */
};

 

SYNOPSIS

#include <sys/types.h>
#include <utime.h>

int utime(const char *filename, const struct utimbuf *times);

#include <sys/time.h>

int utimes(const char *filename, const struct timeval times[2])

샘플 코드

/*
 * main.c
 * 
 * Copyright 2014 Sungtae Kim <pchero21@gmail.com>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 * 
 * 
 */


#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <utime.h>
#include <stdlib.h>
#include <time.h>

void file_stat(struct stat sb);


int main(int argc, char **argv)
{
    struct stat sb[2];
    int i;

    if (argc != 3) {
       fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
       exit(EXIT_FAILURE);
    }
    
    printf("Before utime-----------------------------------\n");
    for(i = 0; i < 2; i++)
    {
        if (stat(argv[i + 1], &sb[i]) == -1) {
            perror("stat");
            exit(EXIT_FAILURE);
        }

        file_stat(sb[i]);
        printf("--------\n");
    }
    
    struct utimbuf ubuf;
    ubuf.actime = sb[0].st_atime;
    ubuf.modtime = sb[0].st_mtime;

    // Let's use utime!
    utime(argv[2], &ubuf);

    printf("\n\nAfter utime-----------------------------------\n");
    for(i = 0; i < 2; i++)
    {
        if (stat(argv[i + 1], &sb[i]) == -1) {
            perror("stat");
            exit(EXIT_FAILURE);
        }
        file_stat(sb[i]);
        printf("--------\n");
    }

    return 0;
}


void file_stat(struct stat sb)
{
    switch (sb.st_mode & S_IFMT) {
        case S_IFBLK:  printf("block device\n");            break;
        case S_IFCHR:  printf("character device\n");        break;
        case S_IFDIR:  printf("directory\n");               break;
        case S_IFIFO:  printf("FIFO/pipe\n");               break;
        case S_IFLNK:  printf("symlink\n");                 break;
        case S_IFREG:  printf("regular file\n");            break;
        case S_IFSOCK: printf("socket\n");                  break;
        default:       printf("unknown?\n");                break;
    }
    
    printf("I-node number:            %ld\n", (long) sb.st_ino);

    printf("Mode:                     %lo (octal)\n",
           (unsigned long) sb.st_mode);

    printf("Link count:               %ld\n", (long) sb.st_nlink);
    printf("Ownership:                UID=%ld   GID=%ld\n",
           (long) sb.st_uid, (long) sb.st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
           (long) sb.st_blksize);
    printf("File size:                %lld bytes\n",
           (long long) sb.st_size);
    printf("Blocks allocated:         %lld\n",
           (long long) sb.st_blocks);

    printf("Last status change:       %s", ctime(&sb.st_ctime));
    printf("Last file access:         %s", ctime(&sb.st_atime));
    printf("Last file modification:   %s", ctime(&sb.st_mtime));
}

 

결과

pchero@MyGalaxy:~/workspace/Study/Program/file/stat_example$ ./main ./test.txt test2.txt 
Before utime-----------------------------------
regular file
I-node number:            12976592
Mode:                     100664 (octal)
Link count:               1
Ownership:                UID=1000   GID=1000
Preferred I/O block size: 4096 bytes
File size:                0 bytes
Blocks allocated:         0
Last status change:       Thu Aug  7 11:08:25 2014
Last file access:         Thu Aug  7 10:56:34 2014
Last file modification:   Thu Aug  7 10:56:34 2014
--------
regular file
I-node number:            12976593
Mode:                     100664 (octal)
Link count:               1
Ownership:                UID=1000   GID=1000
Preferred I/O block size: 4096 bytes
File size:                0 bytes
Blocks allocated:         0
Last status change:       Thu Aug  7 11:11:53 2014
Last file access:         Thu Aug  7 11:11:53 2014
Last file modification:   Thu Aug  7 11:11:53 2014
--------


After utime-----------------------------------
regular file
I-node number:            12976592
Mode:                     100664 (octal)
Link count:               1
Ownership:                UID=1000   GID=1000
Preferred I/O block size: 4096 bytes
File size:                0 bytes
Blocks allocated:         0
Last status change:       Thu Aug  7 11:08:25 2014
Last file access:         Thu Aug  7 10:56:34 2014
Last file modification:   Thu Aug  7 10:56:34 2014
--------
regular file
I-node number:            12976593
Mode:                     100664 (octal)
Link count:               1
Ownership:                UID=1000   GID=1000
Preferred I/O block size: 4096 bytes
File size:                0 bytes
Blocks allocated:         0
Last status change:       Thu Aug  7 11:12:01 2014
Last file access:         Thu Aug  7 10:56:34 2014
Last file modification:   Thu Aug  7 10:56:34 2014
--------

 

 

dirent, stat

이번에 dirent 와 stat 을 이용하여 작업을 하면서 알게된 내용들을 간단하게 정리했다.

dirent

dirent 는 디렉토리 정보를 담는 구조체이다.
dirent 와 scandir() 을 사용하면 디렉토리에 어떤 파일들이 있는지 간략하게 알 수 있는 속성과 파일 리스트 포인터를 이용할 수 있다.

struct dirent
{
#ifndef __USE_FILE_OFFSET64
    __ino_t d_ino;
    __off_t d_off;
#else
    __ino64_t d_ino;
    __off64_t d_off;
#endif
    unsigned short int d_reclen;
    unsigned char d_type;
    char d_name[256];		/* We must not include limits.h! */
};

구조체 내용 중, d_type 으로 파일의 속성을 파악할 수 있는데, 종류는 다음과 같다.

#ifdef __USE_BSD
/* File types for `d_type'.  */
enum
  {
    DT_UNKNOWN = 0,
# define DT_UNKNOWN	DT_UNKNOWN
    DT_FIFO = 1,
# define DT_FIFO	DT_FIFO
    DT_CHR = 2,
# define DT_CHR		DT_CHR
    DT_DIR = 4,
# define DT_DIR		DT_DIR
    DT_BLK = 6,
# define DT_BLK		DT_BLK
    DT_REG = 8,
# define DT_REG		DT_REG
    DT_LNK = 10,
# define DT_LNK		DT_LNK
    DT_SOCK = 12,
# define DT_SOCK	DT_SOCK
    DT_WHT = 14
# define DT_WHT		DT_WHT
  };

/* Convert between stat structure types and directory types.  */
# define IFTODT(mode)	(((mode) & 0170000) >> 12)
# define DTTOIF(dirtype)	((dirtype) << 12)
#endif

 

stat

stat 은 파일 속성을 가져오는 함수이며, 구조체이다. stat 을 호출하면, 입력한 파일에 대한 속성들이 struct stat 구조체에 입력된다.

struct stat {
   dev_t     st_dev;     /* ID of device containing file */
   ino_t     st_ino;     /* inode number */
   mode_t    st_mode;    /* protection */
   nlink_t   st_nlink;   /* number of hard links */
   uid_t     st_uid;     /* user ID of owner */
   gid_t     st_gid;     /* group ID of owner */
   dev_t     st_rdev;    /* device ID (if special file) */
   off_t     st_size;    /* total size, in bytes */
   blksize_t st_blksize; /* blocksize for filesystem I/O */
   blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
   time_t    st_atime;   /* time of last access */
   time_t    st_mtime;   /* time of last modification */
   time_t    st_ctime;   /* time of last status change */
};

 

Eaxmple

아래는 stat 과 scandir 을 이용한 예제 프로그램이다.
현재 디렉토리 내에 있는 모든 파일들을 최근 수정한 순서대로 검색하며 각각의 파일명과 사이즈(Byte)를 표시한다.
만약, 디렉토리 안에 있는 파일들의 용량의 10M가 넘어가면, 그 이후부터는 파일을 삭제한다.

즉, 디렉토리에 있는 파일들의 용량이 10M가 넘어가면 오래된 파일부터 삭제하는 것이다.

그리고 파일을 검색하는 도중 파일명에 .wav(wav 파일)이 들어있으면 “Found wav file” 을 표시한다.

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define TARGET_DIR "."
#define LIMIT_SIZE 10485760 // 10M

int file_select( const struct dirent *d );
int cmp_time(const struct dirent **e1, const struct dirent **e2);


int main(int argc, char** argv)
{
    struct dirent **namelist;
    struct stat tmp_stat;
    unsigned long total_size;
    char* pszFilename;
    int iCnt;
    int i;
    int iRet;
    char* pRet;

    iCnt = scandir(TARGET_DIR, &namelist, file_select, cmp_time);
    if(iCnt < 0)
    {
        printf("Could not scanning.. err:%d, msg:%s\n", errno, strerror(errno));
        return 0;
    }

    total_size = 0;
    printf("Scan files:%d\n", iCnt);
    for(i = 0; i < iCnt; i++)
    {
        asprintf(&pszFilename, "%s/%s", TARGET_DIR, namelist[i]->d_name);
        stat(pszFilename, &tmp_stat);
        printf("filename: %s, size:%ld\n", pszFilename, tmp_stat.st_size);
        pRet = strstr(namelist[i]->d_name, ".wav");
        if(pRet != NULL)
        {
            printf("Found wav file!\n");
        }

        total_size += tmp_stat.st_size;
        if(total_size > LIMIT_SIZE)
        {
            total_size -= tmp_stat.st_size;
            
            printf("Delete limit overed files... name: %s\n", pszFilename);
            iRet = remove(pszFilename);
            if(iRet == -1)
            {
                printf("Err! Could not delete file. name:%s, err:%d, msg:%s\n", pszFilename, errno, strerror(errno));
            }
        }
        
        free(pszFilename);
        free(namelist[i]);
    }
    
    free(namelist);
    
    printf("totalSize %lu\n", total_size);
    
    return 0;
}

/**
 * 
 */
int file_select(const struct dirent *entry)
{
    if(entry->d_type == DT_DIR)
    {
        return 0;
    }

    return 1;
}

/**
 *
 */
int cmp_time(const struct dirent **e1, const struct dirent **e2)
{
    int iRet;
    struct stat sb1;
    struct stat sb2;
    char* filename_e1;
    char* filename_e2;
    
    asprintf(&filename_e1, "%s/%s", TARGET_DIR, (*e1)->d_name);
    asprintf(&filename_e2, "%s/%s", TARGET_DIR, (*e2)->d_name);
        
    iRet = stat(filename_e1, &sb1);
    if(iRet == -1)
    {
        printf("Error occured! name:%s, err:%d, msg:%s\n", filename_e1, errno, strerror(errno));

        free(filename_e1);
        free(filename_e2);
        return -1;
    }
    
    iRet = stat(filename_e2, &sb2);
    if(iRet == -1)
    {
        printf("Error occured! Err:%d, Msg:%s\n", errno, strerror(errno));

        free(filename_e1);
        free(filename_e2);
        return -1;
    }
    
    free(filename_e1);
    free(filename_e2);
    
    return sb1.st_mtime < sb2.st_mtime;
}

Libevent event driven memory leak

진행중인 프로젝트에서 Libevent 를 사용중인데.. valgrind 메모리 누수 확인시 자꾸 메모리 누수가 발생하는 것을 확인했다.

어디가 문제일까… 기능상으로는 문제가 없었다.
malloc/calloc 할당한 부분도 문제가 없었다.
valgrind 가 지목한 문제 발생한 부분은 event_new() 부분이었다.

문제 발생 원인은 잘못된 libevent 사용에 있었다.
나는 다음과 같이 프로그램을 개발했었다.

/*
* main.c
*
* Copyright 2014 Sungtae Kim <pchero21@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <event2/event.h>

typedef struct _wctx
{
struct event_base*  w_base;     // main base
} wctx;

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);

int main(int argc, char **argv)
{

wctx* work = calloc(1, sizeof(wctx));

work->w_base = event_base_new();
struct event* main_listen = event_new(work->w_base, STDIN_FILENO, EV_READ, cb_main_listen, work);
event_add(main_listen, NULL);

event_base_dispatch(work->w_base);

printf(“System terminate…n”);
event_free(main_listen);
event_base_free(work->w_base);

return 0;
}

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
wctx* work = (wctx*)arg;
struct event* w_event = evtimer_new(work->w_base, cb_process, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
evtimer_add(w_event, &tVal);
}

static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Process!!n”);
wctx* work = (wctx*)arg;
struct event* w_event = evtimer_new(work->w_base, cb_process_detail, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
evtimer_add(w_event, &tVal);

}

static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Detail Process!!n”);
}

 

아래는 valgrind 로 메모리 누수를 확인한 내용이다.

pchero@MyGalaxy:~/workspace/Study/Program/LibEvent/memory_leak$ echo “Hello” | valgrind –leak-check=full ./main
==2222== Memcheck, a memory error detector
==2222== Copyright (C) 2002-2012, and GNU GPL’d, by Julian Seward et al.
==2222== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2222== Command: ./main
==2222==
Process!!
Detail Process!!
System terminate…
==2222==
==2222== HEAP SUMMARY:
==2222==     in use at exit: 280 bytes in 3 blocks
==2222==   total heap usage: 12 allocs, 9 frees, 1,848 bytes allocated
==2222==
==2222== 136 bytes in 1 blocks are definitely lost in loss record 2 of 3
==2222==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2222==    by 0x4E43A46: event_new (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x400A16: cb_process (main.c:73)
==2222==    by 0x4E41F93: event_base_loop (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x400933: main (main.c:49)
==2222==
==2222== 144 (136 direct, 8 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
==2222==    at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2222==    by 0x4E43A46: event_new (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x4009A1: cb_main_listen (main.c:61)
==2222==    by 0x4E41F93: event_base_loop (in /usr/lib/x86_64-linux-gnu/libevent-2.0.so.5.1.9)
==2222==    by 0x400933: main (main.c:49)
==2222==
==2222== LEAK SUMMARY:
==2222==    definitely lost: 272 bytes in 2 blocks
==2222==    indirectly lost: 8 bytes in 1 blocks
==2222==      possibly lost: 0 bytes in 0 blocks
==2222==    still reachable: 0 bytes in 0 blocks
==2222==         suppressed: 0 bytes in 0 blocks
==2222==
==2222== For counts of detected and suppressed errors, rerun with: -v
==2222== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)

메모리 누수가 확인되는 지점이 두 곳이 보인다. 모두 event_new 를 했던 곳이다. 내용인즉, event_new() 를 통해 생성한 event를 따로 정상 삭제하지 않았다는 내용이다.
나는 timer 에 등록할 경우, 시간이 되어 함수가 작동할 경우, libevent 에서 자동으로 메모리를 해제해 주는 줄 알았다.
하지만 아니었다…

결국, 소스를 다음과 같이 수정하였다.

/*
* main.c
*
* Copyright 2014 Sungtae Kim <pchero21@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <event2/event.h>

typedef struct _wctx
{
struct event_base*  w_base;     // main base
struct event*       w_event;    // work event
} wctx;

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);
static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg);

int main(int argc, char **argv)
{

wctx* work = calloc(1, sizeof(wctx));

work->w_base = event_base_new();
struct event* main_listen = event_new(work->w_base, STDIN_FILENO, EV_READ, cb_main_listen, work);
event_add(main_listen, NULL);

event_base_dispatch(work->w_base);

printf(“System terminate…n”);
event_free(main_listen);
event_base_free(work->w_base);
free(work);

return 0;
}

static void cb_main_listen(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
wctx* work = (wctx*)arg;
//    struct event* w_event = evtimer_new(work->w_base, cb_process, work);
work->w_event = evtimer_new(work->w_base, cb_process, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
//    evtimer_add(w_event, &tVal);
evtimer_add(work->w_event, &tVal);
}

static void cb_process(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Process!!n”);
wctx* work = (wctx*)arg;
//    struct event* w_event = evtimer_new(work->w_base, cb_process_detail, work);
evtimer_assign(work->w_event, work->w_base, cb_process_detail, work);

struct timeval  tVal;
tVal.tv_sec = 0;
tVal.tv_usec = 0;
//    evtimer_add(w_event, &tVal);
evtimer_add(work->w_event, &tVal);
}

static void cb_process_detail(__attribute__ ((__unused__)) int fd, __attribute__ ((__unused__)) short event, void *arg)
{
printf(“Detail Process!!n”);
wctx* work = (wctx*)arg;
event_free(work->w_event);
}

소스 수정 후, 다시 valgrind 를 돌려보았다.

pchero@MyGalaxy:~/workspace/Study/Program/LibEvent/memory_leak$ echo “Hello” | valgrind –leak-check=full ./main
==2440== Memcheck, a memory error detector
==2440== Copyright (C) 2002-2012, and GNU GPL’d, by Julian Seward et al.
==2440== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==2440== Command: ./main
==2440==
Process!!
Detail Process!!
System terminate…
==2440==
==2440== HEAP SUMMARY:
==2440==     in use at exit: 0 bytes in 0 blocks
==2440==   total heap usage: 11 allocs, 11 frees, 1,720 bytes allocated
==2440==
==2440== All heap blocks were freed — no leaks are possible
==2440==
==2440== For counts of detected and suppressed errors, rerun with: -v
==2440== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

결과는 성공!

문제 해결의 포인트는 다음과 같았다.

1. event_new()/evtimer_new() 의 사용을 줄이는 것. 가능하면 event_assign()/evtimer_assign() 을 사용하도록 했다.
2. new() 가 있으면 free() 도 해 준다는 것.

size_t warning. int’ is smaller than type ‘unsigned long

사내 HP-UX 서버에서 컴파일을 하다, 아래의 Warning 이 나왔다.

Warning (suggestion) 887: “SharedMemory.cpp”, line 711 # Type ‘int’ is smaller than type ‘unsigned long’, unwanted widening in value may result.        memset(szTotalHexData, 0x00, (iSize * 3) + 1);                                      ^^^^^^^^^^^^^^  

이유인즉, unsigned long type 이 와야 하는데, int type 이 왔다는 것.

이상할 것이 없어서 memset man 페이지를 확인해 보았다.

      void *memset(void *s, int c, size_t n);

결론은, 저 size_t 의 type. 그냥 int 형 타입인 줄 알았는데, 그게 아니었다. unsigned long type 이었다.

혹시나 HP-UX aCC 에서만 적용되는건 아닌가 싶어서 g++ 에서도 찾아보았다.

확인 결과, 둘 다 unsigned long type 이 맞았다.

g++-4.7.3

#ifndef __SIZE_TYPE__
#define __SIZE_TYPE__ long unsigned int
#endif
#if !(defined (__GNUG__) && defined (size_t))
typedef __SIZE_TYPE__ size_t;

aCC: HP ANSI C++ B3910B A.03.37

#include <sys/stdsyms.h>

#ifndef _SIZE_T_INCLUDED
#       define _SIZE_T_INCLUDED

#       ifndef _SIZE_T
#               define _SIZE_T
_NAMESPACE_STD_START
                        typedef unsigned long size_t;
_NAMESPACE_STD_END
#       endif /** _SIZE_T **/

#endif /** _SIZE_T_INCLUDED **/