메모리 릭. 고수님들 도와주세요. ㅠㅠ
닷넷 개발을 하다 이번에 리눅스좀 만지고 있는 초보 개발자 입니다.
메모리가 누수되고있는데 어디선지 당췌 알수가 없네요.
대충이라도 좀 짚어주시면 감사하겠습니다. ㅜㅜ
#include <bson.h> #include <json.h> #include <stdio.h> #include <unistd.h> #include <glib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <mongo.h> #include "logfile.h" #define PORT 8899 #define BUFSIZE 65545 static bson *json_to_bson (struct json_object *json); char *strSplit(char recv[BUFSIZE], char *splitStr); static void json_key_to_bson_key (bson *b, void *val, const gchar *key) { switch (json_object_get_type (val)) { case json_type_boolean: bson_append_boolean (b, key, json_object_get_boolean (val)); break; case json_type_double: bson_append_double (b, key, json_object_get_double (val)); break; case json_type_int: bson_append_int32 (b, key , json_object_get_int (val)); break; case json_type_object: { bson *sub; sub = json_to_bson (val); bson_append_document (b, key, sub); bson_free (sub); break; } case json_type_array: { gint pos; bson *sub; sub = bson_new (); for (pos = 0; pos < json_object_array_length (val); pos++) { gchar *nk = g_strdup_printf ("%d", pos); json_key_to_bson_key (sub, json_object_array_get_idx (val, pos), nk); g_free (nk); } bson_finish (sub); bson_append_array (b, key, sub); bson_free (sub); break; } case json_type_string: bson_append_string (b, key, json_object_get_string (val), -1); break; default: break; } } static bson * json_to_bson (struct json_object *json) { bson *b; b = bson_new (); { json_object_object_foreach (json, key, val) { json_key_to_bson_key (b, val, key); } } bson_finish (b); return b; } struct json_object * jsonStr_to_jsonStruct(char *jsonStr) { static struct json_object *json; const GString *json_str = g_string_new(jsonStr); //GError *error = NULL; struct json_tokener *tokener; tokener = json_tokener_new (); //while (g_io_channel_read_line_string (input, json_str, NULL, &error) == G_IO_STATUS_NORMAL) { //struct json_object *json; bson *bson; json_tokener_reset (tokener); json = json_tokener_parse_ex (tokener, json_str->str, json_str->len); if (!json) { //fprintf (stderr, "Error parsing json: %s:%d:%d\n", json_str->str, strlen(json_str->str), json_str->len); //Trace((1,"Error parsing json: %s:%d:%d\n", json_str->str, strlen(json_str->str), json_str->len)); return NULL; } if (json_object_get_type (json) != json_type_object) { fprintf (stderr,"Error: json's top-level object is not object: %s\n",json_str->str); json_object_put (json); return NULL; } /* bson = json_to_bson (json); json_object_put (json); write (1, bson_data (bson), bson_size (bson)); bson_free (bson); */ } json_tokener_free(tokener); g_string_free(json_str, json_str->len); return json; } int main(void) { int sockfd; struct sockaddr_in servAddr; struct sockaddr_in clntAddr; char recvBuffer[BUFSIZE]; int clntLen; int recvLen; char strJSON[BUFSIZE]; if((sockfd=socket(AF_INET, SOCK_DGRAM, 0))==-1){ perror("sock failed"); exit(1); } memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = htonl(INADDR_ANY); servAddr.sin_port = htons(PORT); if(bind(sockfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) == -1) { perror("bind failed"); exit(1); } mongo_sync_connection *conn; conn = mongo_sync_connect ("192.168.10.103", 27017, FALSE); if (!conn) { perror ("mongo_sync_connect()"); exit (1); } char colName[50]; char *tmp; struct json_object *json; char *result; while(1) { clntLen = sizeof(clntAddr); if((recvLen=recvfrom(sockfd, recvBuffer, BUFSIZE-1, 0, (struct sockaddr*)&clntAddr, &clntLen))== -1) { perror("recvfrom failed"); exit(1); } //printf("%d\n", /*recvBuffer,*/ recvLen); //char *strJSON; memset(strJSON, 0, BUFSIZE); tmp = strSplit(recvBuffer, "}{"); if(tmp == NULL || tmp == 0) continue; strcpy(strJSON, tmp); //free(tmp); while(1) { if(strstr(strJSON, "{\"type\":\"AGENT\"")!=NULL) { strcpy(colName, "db.AGENT\0"); } else if(strstr(strJSON, "{\"type\":\"ASSSET\"")!=NULL) { strcpy(colName, "db.ASSSET\0"); } else if(strstr(strJSON, "{\"type\":\"ASSSETITEM\"")!=NULL) { strcpy(colName, "db.ASSSETITEM\0"); } else if(strstr(strJSON, "{\"type\":\"EVENT\"")!=NULL) { strcpy(colName, "db.EVENT\0"); } else if(strstr(strJSON, "{\"type\":\"PERF\"")!=NULL) { strcpy(colName, "db.PERF\0"); } else if(strstr(strJSON, "{\"type\":\"PERFITEM\"")!=NULL) { strcpy(colName, "db.PERFITEM\0"); } else if(strstr(strJSON, "{\"type\":\"REAL\"")!=NULL) { strcpy(colName, "db.REAL\0"); } else if(strstr(strJSON, "{\"type\":\"REALITEM\"")!=NULL) { strcpy(colName, "db.REALITEM\0"); } else { continue; } json = jsonStr_to_jsonStruct(strJSON); if(json == NULL) { //free(json); break; } bson *b = json_to_bson(json); if (!mongo_sync_cmd_insert (conn, colName, b, NULL)) { perror ("mongo_sync_cmd_insert()"); exit (1); } else { //printf("OK:%s:%d\n",strJSON, strlen(strJSON)); } //free(colName); bson_free (b); if(b == NULL) break; result = strSplit(NULL, "}{"); if(result == NULL) break; strcpy(strJSON, result); //free(result); if(strJSON == NULL || strlen(strJSON) == 0) { break; } } } printf("END\n"); mongo_sync_disconnect (conn); } char *strSplit(char recv[BUFSIZE], char *splitStr) { static char strBuffer[BUFSIZE]; static int IsEnd = 0; static char result[BUFSIZE]; static char *ptr; static char tmpResult [BUFSIZE]; static int nLenStrBuffer; static int nLenPtr; static int nEnd; if(IsEnd) { IsEnd = 0; return NULL; } if(recv!=NULL) { memset(strBuffer, 0, BUFSIZE); strcpy(strBuffer, recv); //free(recv); } ptr = strstr(strBuffer, splitStr); if(ptr == NULL) { IsEnd = 1; free(ptr); return strBuffer; } else { memset(tmpResult, 0, BUFSIZE); strcpy(tmpResult, ptr); nLenStrBuffer = strlen(strBuffer); nLenPtr = strlen(ptr)-1; //free(ptr); nEnd = nLenStrBuffer - nLenPtr; memset(result, 0, BUFSIZE); strncpy(result, strBuffer, nEnd); //printf("strSplit:%d\n", /*result,*/ nEnd); memset(strBuffer, 0, BUFSIZE); strcpy(strBuffer, tmpResult+1); //free(tmpResult); return result; } }
아래는 valgrind --leak-check=full mongoTest 결과입니다. ㅠㅠ
==13484== Memcheck, a memory error detector
==13484== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==13484== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==13484== Command: mongoTest
==13484==
^C==13484==
==13484== HEAP SUMMARY:
==13484== in use at exit: 586,569 bytes in 9,572 blocks
==13484== total heap usage: 15,180 allocs, 5,608 frees, 1,344,726 bytes allocated
==13484==
==13484== 496 bytes in 1 blocks are possibly lost in loss record 22 of 43
==13484== at 0x4C29BE8: memalign (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13484== by 0x4C29C97: posix_memalign (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13484== by 0x52670C9: slab_allocator_alloc_chunk (gslice.c:1381)
==13484== by 0x52AE088: g_slice_alloc (gslice.c:719)
==13484== by 0x5269CE9: g_array_sized_new (garray.c:195)
==13484== by 0x503E8D4: bson_new_sized (bson.c:262)
==13484== by 0x4054C9: json_to_bson (mongoTest.c:81)
==13484== by 0x4059E2: main (mongoTest.c:263)
==13484==
==13484== 1,488 bytes in 3 blocks are possibly lost in loss record 29 of 43
==13484== at 0x4C29BE8: memalign (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13484== by 0x4C29C97: posix_memalign (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13484== by 0x52670C9: slab_allocator_alloc_chunk (gslice.c:1381)
==13484== by 0x52AE0B3: g_slice_alloc (gslice.c:724)
==13484== by 0x5269CE9: g_array_sized_new (garray.c:195)
==13484== by 0x503E8D4: bson_new_sized (bson.c:262)
==13484== by 0x4054C9: json_to_bson (mongoTest.c:81)
==13484== by 0x4059E2: main (mongoTest.c:263)
==13484==
==13484== 13,450 (240 direct, 13,210 indirect) bytes in 5 blocks are definitely lost in loss record 32 of 43
==13484== at 0x4C29DB4: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13484== by 0x4E348F1: json_object_new (json_object.c:164)
==13484== by 0x4E34D5A: json_object_new_object (json_object.c:243)
==13484== by 0x4E3641E: json_tokener_parse_ex (json_tokener.c:217)
==13484== by 0x4055A3: jsonStr_to_jsonStruct (mongoTest.c:111)
==13484== by 0x4059BE: main (mongoTest.c:255)
==13484==
==13484== 495,798 (1,072 direct, 494,726 indirect) bytes in 1 blocks are definitely lost in loss record 43 of 43
==13484== at 0x4C29DB4: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13484== by 0x4E3543F: json_tokener_new (json_tokener.c:66)
==13484== by 0x40556A: jsonStr_to_jsonStruct (mongoTest.c:102)
==13484== by 0x4059BE: main (mongoTest.c:255)
==13484==
==13484== LEAK SUMMARY:
==13484== definitely lost: 1,312 bytes in 6 blocks
==13484== indirectly lost: 507,936 bytes in 9,518 blocks
==13484== possibly lost: 1,984 bytes in 4 blocks
==13484== still reachable: 75,337 bytes in 44 blocks
==13484== suppressed: 0 bytes in 0 blocks
==13484== Reachable blocks (those to which a pointer was found) are not shown.
==13484== To see them, rerun with: --leak-check=full --show-reachable=yes
==13484==
==13484== For counts of detected and suppressed errors, rerun with: -v
==13484== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 2 from 2)
jsonStr_to_jsonStruct 함수에서
jsonStr_to_jsonStruct 함수에서 json_tokener_new로 생성한 tokener를 return NULL; 실행 전에 json_tokener_free으로 해제해줘야 할 것 같아요.
——
———
Life is a tragedy when seen in close-up, but a comedy in long-shot. - Chaplin, Charlie -
감사합니다.
감사합니다~
말슴대로
json_tokener_free(tokener);
g_string_free(json_str, json_str->len);
구문을 넣어 대부분 잡히긴 했는데
top -p pid 로 해서 검색해보니
64byte, 4byte 씩 주기적으로 올라가는게 있었습니다.
64byte 는 구조체 같고. 4 byte 는 포인터라고 예상이 되긴 하는데.. 맞을까요?
눈빠지게 보고 있네요 ^^ 도와주셔서 감사합니다. ^^
valgrind 실행 결과에서 definitely
valgrind 실행 결과에서 definitely lost 부분을 먼저 하나 하나씩 잡아 가면 됩니다.
나머지 lost는 definitely lost 때문에 나는 경우가 있어서요.
definitely lost 부분의 콜 스택을 유심히 살펴보고 함수가 종료될 때 자원 해제를 하지 않은 것이 있는지 확인해 보세요.
——
———
Life is a tragedy when seen in close-up, but a comedy in long-shot. - Chaplin, Charlie -
댓글 달기