2013-12-08 209 views
0

我正在尝试Windows中的GTK应用程序,并且刚开始学习GTK。解决GTK + /队列中的窗口内存泄漏问题

GTK版本:

gtk+-bundle_2.24.10-20120208_win32 

应用需求:

1. Multi threaded 
2. Queue based communication 
3. GTK window to update a image data in screen with 5 secs delay 

应用功能:

1. 2 thread (producer and other consumer) 
    Producer will post a string to queue manager which will form a structure and post the data to the respective queue 
2. Upon posting the data to the queue manager producer thread shall update the respective image on the screen 
3. Consumer will be monitoring the queue and on receiving data consumer will process the data according 

The application is running as expected: 

我面对这里的问题是内存(根据Windows资源监视器)

Confused which one is causing the LEAK -- GTK or my queue or ??? 

    the program starts with 26K memory and on certain time it reaches 190000K memory. So i see memory leak 
    request some guidance in handling this issue 

这是我工作的示例程序流程。

#include <stdio.h> 
#include <glib.h> 
#include <gtk/gtk.h> 
#include <windows.h> 

#define sleep(n) g_usleep(1000 * n) 

G_LOCK_DEFINE_STATIC (queue_memchunk); 
static GMemChunk *queue_memchunk = NULL; 
static GTrashStack *free_queue_nodes = NULL; 
GQueue* msgQueueId[7]; 


#define NORMAL_TEXT  0 
#define WARNING_TEXT 1 
#define STATUS_TEXT  2 
#define NORMAL_FONT  0 
#define SMALL_FONT  1 
#define NORM_FONT_UNLTD 2 
#define MAX_MSG_SIZE  5120 
#define TRACK_ONE_SIZE  150 
#define TRACK_TWO_SIZE  100 
#define TRACK_THREE_SIZE 100 
#define FSM_CHANNEL  1 



typedef struct 
{ 
    int msgType; 
    int msgSize; 
    char msgBuf[MAX_MSG_SIZE]; 
}STRUCT_MSG; 

GtkWidget* window; 

struct WidgetsAlive 
{ 
    GtkWidget* widPtr; 
    int widIndex; 
    struct WidgetsAlive* dependants; 
    struct WidgetsAlive* next; 
}; 

/* Linked list ptr to the widgets alive */ 
static struct WidgetsAlive* wAlive = NULL; 
static struct WidgetsAlive* depFirstNode = NULL; 
typedef struct { 
    char* fileName; 
    }dispTextPage_struct; 

    typedef struct { 
     char* data; 
     int row; 
     int column; 
     char textType; 
     char fontType; 
     }updateTextPage_struct; 

int waitForLoop; 

void dispInit(int argc, char* argv[]); 
void dispInfoPage(char* fileName, int duration); 
gboolean dispTextPage_callBack(dispTextPage_struct *params); 
int dispTextPage(char* fileName, int duration); 


int destroyNotify(void){ 
    printf("Notfiy called in"); 
    while (gtk_events_pending()) 
      { 
      g_usleep (1); 
      gtk_main_iteration_do(FALSE); 
      } 
    waitForLoop = 0; 
    return 0; 

} 


gpointer main_callback(gpointer data) 
{ 
    gtk_main(); 
    return 0; 
} 

void dispInit(int argc, char* argv[]) 
{ 
    printf("Initializing the display library\n"); 
    gtk_init(&argc, &argv); 
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
    gtk_window_resize(GTK_WINDOW(window), 640, 480); 
    gtk_window_set_default_size(GTK_WINDOW(window), 640, 480); 
    gtk_widget_realize(window); 
    gtk_window_set_decorated(GTK_WINDOW(window), FALSE); 
    g_thread_create(main_callback, NULL, FALSE, NULL); 
} 

void dispInfoPage(char* fileName, int duration) 
{ 
    int index; 
    gdk_threads_enter(); 
    destroyWidget(0); 
    GtkWidget *image; 
    image = gtk_image_new_from_file(fileName); 
    gtk_container_add(GTK_CONTAINER(window), image); 
    gtk_widget_show(image); 
    gtk_widget_show(window); 
    gdk_threads_leave(); 
} 

struct WidgetsAlive* getWidgetFromList(int widgetIndex) 
{ 
     struct WidgetsAlive *temp, *prev; 
     temp = wAlive; 
     prev = NULL; 
     if (temp == NULL) 
     { 
       /* Widget list is empty. Nothing to destroy */ 
       return NULL; 
     } 
     else 
     { 
      while(temp != NULL) 
      { 
       if(temp->widIndex == widgetIndex) 
       { 
         return temp; 
       } 
       else 
       { 
         //printf("Iterating to the next widget in the list, since the index is different\n"); 
         prev = temp; 
         temp = temp->next; 
       } 
      } 
     //printf("No widget with index %d found to destroy, Please check the index..\n", index); 
     } 
    return NULL; 
} 

int destroyWidget(int index) 
{ 
    GList *children, *iter; 
     struct WidgetsAlive *temp, *prev, *next, *depTemp; 
     temp = wAlive; 
     prev = wAlive; 
     gtk_window_resize((GtkWindow*)window, 800, 600); 
     children = gtk_container_get_children(GTK_CONTAINER(window)); 
     for(iter = children; iter != NULL; iter = g_list_next(iter)){ 
      gtk_container_remove(GTK_CONTAINER(window),GTK_WIDGET(iter->data)); 
      //printf("Deleting Widget\n"); 
     } 
     g_list_free(iter); 
     g_list_free(children); 

    gtk_window_resize((GtkWindow*)window, 800, 600); 
    /* if (temp == NULL) 
    { 
     return; 
    } 
    else 
    { 
     if (temp->widIndex == index) 
     { 
      if (temp->widPtr != NULL) 
      { 
       if (GTK_IS_WIDGET(temp->widPtr)) 
       { 
        //gtk_widget_destroy((GtkWidget*)temp->widPtr); 
        printf("Destroying widget Done\n"); 
       } 
      } 
      depTemp = depFirstNode; 
      next = depFirstNode; 
      while (depTemp != NULL) 
      { 
       depTemp = depTemp->next; 
       free(next); 
       next = NULL; 
       next = depTemp; 
      } 
      depFirstNode = NULL; 
      wAlive = NULL; 
      free(temp); 
      temp = NULL; 
      return; 
     } 
     else 
     { 
      while(temp != NULL) 
      { 
       if(temp->widIndex == index) 
       { 
        printf("Found widget match\n"); 
        if (temp->widPtr != NULL) 
        { 
         if (GTK_IS_WIDGET(temp->widPtr)) 
         { 
          //gtk_widget_destroy((GtkWidget*)temp->widPtr); 
         } 
        } 
        prev->next = temp->next; 
        free(temp); 
        temp = NULL; 
        return; 
       } 
       else 
       { 
        prev = temp; 
        temp = temp->next; 
       } 
      } 
     } 
    }*/ 
} 


int addToWidgetsAlive(GtkWidget* inWidget, struct WidgetsAlive* dependants) 

{ 
    /*struct WidgetsAlive *temp, *node; 
    node = (struct WidgetsAlive*)malloc(sizeof(struct WidgetsAlive)); 
    node->widPtr = inWidget; 
    node->widIndex = 1; 
    if (dependants != NULL) 
     node->dependants = dependants; 
    else 
     node->dependants = NULL; 
    node->next = NULL; 
    if (wAlive == NULL) 
    { 
     wAlive = node; 
    } 
    else 
    { 
     temp = wAlive; 
     while(temp->next != NULL) 
     { 
      temp = temp->next; 
     } 
     node->widIndex = temp->widIndex + 1; 
     temp->next = node; 
    } 
    return node->widIndex;*/ 
    return 0; 
} 

int dispTextPage(char* fileName, int duration) 
{ 
//dispTextPage_struct *params; 
    dispTextPage_struct *params; 
    params = (dispTextPage_struct*)malloc(sizeof(dispTextPage_struct)); 
    params->fileName = fileName; 
    /* 
    memset(&params2,'\0',sizeof(dispTextPage_struct)); 
    params2.fileName = fileName;*/ 
    while(gtk_events_pending()){ 
     gtk_main_iteration_do(FALSE); 
     g_usleep(1000); 
    } 
    printf("Gidel added \n"); 
    waitForLoop=1; 
    g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,dispTextPage_callBack,params,destroyNotify); 
    while(waitForLoop == 1){ 
     g_usleep(1000); 
    } 
    free(params); 
} 


gboolean dispTextPage_callBack(dispTextPage_struct *params) 
{ 
    char* fileName = params -> fileName; 
    int index; 
    int isJustifyCenter = 0; 

    GtkWidget *textv; 
    GdkWindow *textv_window; 
    GdkPixmap *pixmap; 
    GtkTextBuffer* textBuffer; 
    GdkColor color; 
    printf("\ntextpage :,1\n"); 
    destroyWidget(0); 
    textv = gtk_text_view_new(); 
    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textv), 22); 
    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(textv), 20); 
    gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(textv),1); 
    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textv), GTK_WRAP_CHAR); 
    if (isJustifyCenter == 1) 
    { 
     gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_CENTER); 
    } 
    else 
    { 
     gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_LEFT); 
    } 

    gtk_text_view_set_editable(GTK_TEXT_VIEW(textv), FALSE); 
    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textv), FALSE); 

    gtk_container_add(GTK_CONTAINER(window), textv); 
    printf("\ntextpage :,3\n"); 
    textv_window = gtk_text_view_get_window (GTK_TEXT_VIEW (textv),GTK_TEXT_WINDOW_TEXT); 
    gdk_color_parse ("#68604d", &color); 
    pixmap = gdk_pixmap_create_from_xpm ((GdkDrawable *) textv_window, NULL,&color, fileName); 
    printf(" textpage :,4\n"); 
    gdk_window_set_back_pixmap (textv_window, pixmap, FALSE); 
    g_object_unref(pixmap); 
    textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textv)); 
    gtk_text_buffer_create_tag (textBuffer, "bold","foreground", "Black", NULL); 
    gtk_text_buffer_create_tag (textBuffer, "Redbold","foreground", "Red",NULL); 
    gtk_text_buffer_create_tag (textBuffer, "fontSize","font", "saxmono 20",NULL); 
    gtk_text_buffer_create_tag (textBuffer, "smallFontSize", "font", "saxmono 14", NULL); 
    gtk_text_buffer_create_tag (textBuffer, "fontweight","weight", 1000,NULL); 
    index = addToWidgetsAlive(textv, NULL); 
    gtk_widget_show(textv); 
    gtk_widget_show(window); 
//free(params); 
return 0; 
} 
gboolean updateTextPage_callBack(updateTextPage_struct *params) 
{ 
    char* data = params -> data; 
    int row = params -> row; 
    int column = params -> column; 
    char textType = params -> textType; 
    char fontType = params -> fontType; 
    int i; 
    int j; 
    struct WidgetsAlive* textWindowWidget = NULL; 
    GtkWidget *tempTextWidgetPtr; 
    GtkTextBuffer *textBuffer; 
    gchar* tempLineStr; 
    char temp[512]; 

    GtkTextIter endIter; 
    GtkTextIter startIter; 
    if(fontType == NORMAL_FONT) 
    { 
     if(row >15 || row < 0) 
      row =15; 
     if(column >31 || column < 0) 
      column =0; 
    } 
    // If there is no valid string to write, return 
    if ((data == NULL) || (strlen(data) == 0)){ 
     free(params); 
     return FALSE; 
    } 
    textWindowWidget = getWidgetFromList(1); 
    if (textWindowWidget != NULL) 
    { 
     tempTextWidgetPtr = textWindowWidget->widPtr; 
    } 
    else 
    { 
     /* Error */ 
     free(params); 
     return FALSE; 
    } 
    textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tempTextWidgetPtr)); 
    gtk_text_buffer_get_end_iter (textBuffer, &endIter); 
    gtk_text_buffer_get_start_iter (textBuffer, &startIter); 
    i = gtk_text_buffer_get_line_count(textBuffer); 
    memset(temp, '\0', sizeof(temp)); 
    if (i < (row+1)) 
    { 
     for (j = i; j < (row + 1); j++) 
     { 
      strcat(temp, "\n"); 
     } 
     //Move one char forward if you are at the newline char 
     while ((gtk_text_iter_get_char(&endIter) != 0)) 
     { 
      gtk_text_iter_forward_char(&endIter); 
     } 
     gtk_text_buffer_insert(textBuffer,&endIter, temp, -1); 
     gtk_text_buffer_get_end_iter (textBuffer, &endIter); 
     gtk_text_buffer_get_iter_at_line(textBuffer, &endIter, row); 
     memset(temp, '\0', sizeof(temp)); 
     for (j = 0; j < column+1; j++) 
     { 
      strcat(temp, " "); 
     } 
     gtk_text_buffer_insert(textBuffer, &endIter, temp, -1); 
    } 
    else 
    { 
     gtk_text_buffer_get_iter_at_line(textBuffer, &startIter, row); 
     gtk_text_buffer_get_iter_at_line(textBuffer, &endIter, row); 
     gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(tempTextWidgetPtr), &endIter); 
     tempLineStr = gtk_text_buffer_get_text(textBuffer, &startIter, &endIter, FALSE); 
     memset(temp, '\0', sizeof(temp)); 
     i = strlen(tempLineStr); 
     if (column > i) 
     { 
      for (j = 0; j < (column - i); j++) 
      { 
       strcat(temp, " "); 
      } 
      gtk_text_buffer_insert(textBuffer,&endIter, temp, -1); 
     } 
    } 
    gtk_text_buffer_get_iter_at_line_offset(textBuffer, &startIter, row, column); 
    endIter = startIter; 
    i = strlen(data); 
    j = 0; 
    while (j < i) 
    { 
     if ((gtk_text_iter_get_char(&endIter) == '\n')) 
     { 
      gtk_text_iter_backward_char(&endIter); 
      break; 
     } 
     gtk_text_iter_forward_char(&endIter); 
     j++; 
    } 
    if (gtk_text_iter_compare(&endIter, &startIter) == 1) // delete only if enditer is greater than startiter 
     gtk_text_buffer_delete(textBuffer, &startIter, &endIter); 
    memset(temp, '\0', sizeof(temp)); 
    j = strlen(data); 
    if (((j + column) > 32) && (fontType == NORMAL_FONT)) 
    { 
     strncpy(temp, data, (32 - column)); 
    } 
    else 
    { 
     strncpy(temp, data, j); 
    } 
    gtk_text_buffer_insert(textBuffer,&startIter, temp, -1); 

    gtk_text_buffer_get_end_iter (textBuffer, &endIter); 
    gtk_text_buffer_get_start_iter (textBuffer, &startIter); 
    if(textType==NORMAL_TEXT) 
     gtk_text_buffer_apply_tag_by_name (textBuffer, "bold", &startIter, &endIter); 
    else 
    { 
     gtk_text_buffer_get_iter_at_line_offset(textBuffer, &startIter, row, column); 
     gtk_text_buffer_apply_tag_by_name (textBuffer, "Redbold", &startIter, &endIter); 
    } 
    if((fontType == NORMAL_FONT) || (fontType == NORM_FONT_UNLTD)) 
    { 
     gtk_text_buffer_apply_tag_by_name (textBuffer, "fontSize", &startIter, &endIter); 
    } 
    else 
    { 
     gtk_text_buffer_get_iter_at_line_offset(textBuffer, &startIter, row, column); 
     gtk_text_buffer_apply_tag_by_name (textBuffer, "smallFontSize", &startIter, &endIter); 
    } 
    gtk_text_buffer_apply_tag_by_name (textBuffer, "fontweight", &startIter, &endIter); 
    gtk_widget_show(tempTextWidgetPtr); 
    gtk_widget_show_all(window); 
    free(params); 
    return FALSE; 
} 


void updateTextPage(char* data, int row, int column,char textType,char fontType) 
{ 
    updateTextPage_struct *params; 
    params = (updateTextPage_struct*)malloc(sizeof(updateTextPage_struct)); 
    params->data = data; 
    params->row = row; 
    params->column = column; 
    params->textType = textType; 
    params->fontType = fontType; 
    while(gtk_events_pending()) 
    { 
     usleep(1000); 
    } 
    waitForLoop=1; 
    g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,updateTextPage_callBack,params,destroyNotify); 
    while(waitForLoop == 1){ 
     usleep(1000); 
    } 
} 

void *fsmThread_RunFunction1() 
    { 

    int atmMsgRetVal; 
    static STRUCT_MSG atmRxMsg; 
    while(1) 
    { 
     memset(&atmRxMsg,'\0',sizeof(STRUCT_MSG)); 
     atmMsgRetVal = PendMessageQ(FSM_CHANNEL,&atmRxMsg); 
     if(atmMsgRetVal == 0) 
     { 

      if(ProcessfsmMessage(atmRxMsg.msgType, (char *)atmRxMsg.msgBuf)) 
       continue; 
     } 
     else{ 
      //sleep(1); 
      usleep(10*1000); 
     } 
    } 
    } 

int ProcessfsmMessage(int msgType, char *msgBuf) 
{ 
    printf("fsmThread_RunFunction data recieved %s\n",msgBuf); 



} 

void *fsmThread_RunFunction() 
{ 
    int pollMsgRetVal = -1; 
    sleep(5000); 
    dispTextPage("icon132.gif",0); 
    char data[500] = "FSM POST MESSAGE\n"; 
    while(1){ 

     printf("Now Entry for fsmThread_RunFunction\n"); 
     PostMessageQ(FSM_CHANNEL,1, data,strlen(data)); 
     dispTextPage("icon165.gif",0); 
     sleep(500); 
     printf("Now Exit for fsmThread_RunFunction\n"); 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    GThread *fsmThreadId,*fsmThreadId1; 
    GError *error = NULL; 
    g_thread_init(NULL); 
    //dispInit(argc, argv); 

    // sleep(5000); 
    CreateMessageQ(FSM_CHANNEL); 
    printf("Initializing the display library\n"); 
    gtk_init(&argc, &argv); 
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
    gtk_window_resize(GTK_WINDOW(window), 640, 480); 
    gtk_window_set_default_size(GTK_WINDOW(window), 640, 480); 
    gtk_widget_realize(window); 
    gtk_window_set_decorated(GTK_WINDOW(window), FALSE); 


    dispInfoPage("icon165.gif",1); 
    sleep(5000); 
    printf("Now create ethread "); 
    fsmThreadId = g_thread_create(fsmThread_RunFunction,NULL,TRUE,&error); 
    if (error) { 
     fflush(stderr); 
     exit(1); 
    } 
    fsmThreadId1 = g_thread_create(fsmThread_RunFunction1,NULL,TRUE,&error); 
    if (error) { 
     fflush(stderr); 
     exit(1); 
    } 

    gtk_main(); 

    g_thread_join(fsmThreadId); 
    sleep(2); 

    printf("ENd of main"); 
    return 0; 
} 


int PostMessageQ(int channel, int msgType, char *msgBuf, int msgSize) 
{ 
    STRUCT_MSG txMsg; 
    memset(&txMsg,'\0',sizeof(STRUCT_MSG)); 
    txMsg.msgType = msgType; 
    txMsg.msgSize = msgSize; 
    memcpy(&txMsg.msgBuf[0],&msgBuf[0],msgSize); 
    g_queue_push_head (msgQueueId[channel], (char *)&txMsg); 
    return 0; 
} 

int PendMessageQ(int channel,STRUCT_MSG* rxMsgptr) 
{ 
    if (g_queue_is_empty(msgQueueId[channel])){ 
     return 1; 
    } 
    STRUCT_MSG* rxMsg = (STRUCT_MSG*) malloc(sizeof(STRUCT_MSG)); 
    rxMsg = (STRUCT_MSG*) g_queue_pop_tail (msgQueueId[channel]); 
    rxMsgptr->msgType = rxMsg->msgType; 
    rxMsgptr->msgSize = rxMsg->msgSize; 
    memcpy(&rxMsgptr->msgBuf[0],&rxMsg->msgBuf[0],sizeof(rxMsg->msgBuf)); 
    free(rxMsg); 
    return 0; 
} 


void CreateMessageQ (int channel) 
{ 
    G_LOCK (queue_memchunk); 
    msgQueueId[channel] = g_trash_stack_pop (&free_queue_nodes); 

    if (!msgQueueId[channel]) 
    { 
     if (!queue_memchunk) 
     queue_memchunk = g_mem_chunk_new ("GLib GQueue chunk", 
              sizeof (GNode), 
              sizeof (GNode) * 128, 
              G_ALLOC_ONLY); 
     msgQueueId[channel] = g_chunk_new (GQueue, queue_memchunk); 
    } 
    G_UNLOCK (queue_memchunk); 

    msgQueueId[channel]->head = NULL; 
    msgQueueId[channel]->tail = NULL; 
    msgQueueId[channel]->length = 0; 
} 
+0

GTK3(至少在Linux上)在启动时使用一些重要的内存来存储一次性资源(如字体,位图,图像等)。如果内存保持在180M字节,我不会惊慌;如果它继续增长,担心。并使用内存泄漏检测器(如Linux上的[valgrind](http://valgrind.org/)),也可以编译所有警告,例如'gcc -Wall -g'。顺便说一下,Linux可能是比Windows更好的GTK开发平台(您可以开始在Linux上开发,并在软件成熟时移植到Windows)。 –

+0

@BasileStarynkevitch ::我一直在工作的代码来自我们现有的5年以上的linux应用程序。 – Ragav

+0

然后在Linux上改进它(对于GTK3),使用'valgrind'来检查内存泄漏,然后将它移植到Windows。 –

回答

1

你不给我们GTK的版本,您正在使用,但机会是,这是一些旧的GTK 2版本的一个已知的问题。检查我对这个问题的回答:https://stackoverflow.com/a/12950519/518853

订阅bug 707760来跟踪包更新。

+0

gtk + -bundle_2.24.10-20120208_win32。如果这个版本有问题,你可以在GTK2基础版中推荐什么是最好的版本 – Ragav

+1

与我指出的答案中的评论相同:降级到2.24.0([下载2.24.x捆绑软件](http:// ftp .gnome.org/pub/gnome/binaries/win32/gtk +/2.24 /)),或者自己构建最新的2.24.x> = 2.24.14。 – liberforce

+0

感谢这指出我找到了除了这个漏洞之外的程序中的泄漏之一,我也在我的队列机制和程序错误泄漏。 1.使用不需要的GQUEUE创建 - g_QUEUE_NEW()2.和在挂起数据中2.错过了空闲。如果你能指出一些会有所帮助的。发出同样的答案。 – Ragav

0
  1. 无用的GQueue创建用于所以改变CreateMessageQ如下:

    空隙CreateMessageQ(INT信道) { msgQueueId [频道] = g_queue_new(); }

  2. 变化PendMessageQ自由是问题:

    INT PendMessageQ(INT信道,STRUCT_MSG * rxMsgptr) { 而(g_queue_is_empty(msgQueueId [频道])){ g_usleep(10 * 1000) ; } char data =(data)g_queue_pop_tail(msgQueueId [channel]); memcpy(& rxMsgptr-> msgBuf [0],& data [0],sizeof(data)); 免费(数据); return 0; }