메모리 릭. 고수님들 도와주세요. ㅠㅠ

hell8032의 이미지

닷넷 개발을 하다 이번에 리눅스좀 만지고 있는 초보 개발자 입니다.

메모리가 누수되고있는데 어디선지 당췌 알수가 없네요.

대충이라도 좀 짚어주시면 감사하겠습니다. ㅜㅜ

#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)

empty2fill의 이미지

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 -

hell8032의 이미지

감사합니다~

말슴대로

json_tokener_free(tokener);
g_string_free(json_str, json_str->len);

구문을 넣어 대부분 잡히긴 했는데

top -p pid 로 해서 검색해보니
64byte, 4byte 씩 주기적으로 올라가는게 있었습니다.

64byte 는 구조체 같고. 4 byte 는 포인터라고 예상이 되긴 하는데.. 맞을까요?

눈빠지게 보고 있네요 ^^ 도와주셔서 감사합니다. ^^

empty2fill의 이미지

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 -

댓글 달기

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 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.