메모리 릭. 고수님들 도와주세요. ㅠㅠ
닷넷 개발을 하다 이번에 리눅스좀 만지고 있는 초보 개발자 입니다.
메모리가 누수되고있는데 어디선지 당췌 알수가 없네요.
대충이라도 좀 짚어주시면 감사하겠습니다. ㅜㅜ
#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 -
댓글 달기