1

これは、リソースの使用を扱うGTK2に関する私の最後の質問のフォローアップです。

GtkImagesアプリケーションは画像を適切に表示していますが、ディスクからロードされ、絶対位置に固定フレームに配置されるたびに、メモリがリークしているように見えます。

数秒ごとに呼び出される次の基本的な方法を使用して、さまざまな画像のセットを読み込んで表示しています。

int DisplaySymbols( GameInfo *m )
{
    // variable declarations removed for brevity 
    // error checking needs to be added
    GtkWidget *image;

    pos_y = 150;
    for( y = 0; y < 3; y++ )
    {
    pos_x = 187;
        for( x = 0; x < 5; x++ )
        {
            image=gtk_image_new_from_file( fileName );
            gtk_fixed_put(GTK_FIXED(frame), image, pos_x, pos_y);
        pos_x += symbols[i].pixel_width;
        }
    pos_y += symbols[i].pixel_height;
    }
    gtk_widget_show_all(window);
    return( 0 );
} 

リソースの使用に関するドキュメントの一部を読みましたが、メモリリークを防ぐために呼び出しをGTK+使用する方法を完全に理解することはできません。API

私が持っているいくつかの考えや質問:

  • フレームに配置された画像をより簡単に管理するために、固定フレームに画像保持ウィジェットを作成する必要がありますか?
  • 私のコードは何をしているのか、していないので、メモリがリークしていますか?GtkImageウィジェットをリリースしない可能性がありますか?
  • 使用するたびにディスクからイメージをロードするのは少し非効率的なようです。それらをメモリに読み込んで、必要に応じてフレームに表示するにはどうすればよいですか?

部分的なソースコードは次のとおりです。

//Compile me with: gcc -o leak leak.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)

// include files removed for brevity
/* GTK */
#include <gdk/gdkx.h>
#include <gtk/gtk.h>

typedef struct
{
    unsigned int pixel_width, pixel_height;
    gchar fileName[20];
}symbol_t;

static symbol_t symbols[] =
{
    /* only showing 2 of eight - brevity */
    { 118, 107, "images/LO.jpg" },
    { 118, 107, "images/L1.jpg" }
};

typedef struct
{
    char SpinResult[3][5];      // index of images pointing into symbols struct
}GameInfo;

GameInfo egm;

GtkWidget *frame;       /* for absolute positionining of widgets */
GtkWidget *window;

/**** prototypes ****/
    // remove for brevity
/********************/

// init random number generator
int Init( void )
{
    // create random number - brevity
}

// Determine spin outcome and store into egm.SpinResult array
int DoSpin( GameInfo *egm )
{
    // generate matrix of indexes into symbols structure
    // so we know what symbols to display in the frame
}

int DisplaySymbols( GameInfo *egm )
{
    // variable declarations removed - brevity
    GtkWidget *image;

    pos_y = 150;
    for( y = 0; y < 3; y++ )
    {
        pos_x = 187;
        for( x = 0; x < 5; x++ )
        {
            image = gtk_image_new_from_file( symbols[i].fileName );             
            gtk_fixed_put(GTK_FIXED(frame), image, pos_x, pos_y);
            pos_x += symbols[i].pixel_width;
        }
        pos_y += symbols[i].pixel_height;
    }
    gtk_widget_show_all(window);
    return( 0 );
} 

void btnSpin_clicked(GtkWidget *button, gpointer data)
{
    DoSpin( &egm );
    DisplaySymbols( &egm );
    return;
}

GtkWidget *SetupWindow(gchar *data, const gchar *filename)
{
    // window setup code removed for brevity    
    return(window);
}

int main (int argc, char *argv[])
{
    GtkWidget *btnSpin, *btnExit;
    float spinDelay = 2.0;     

    Init();    
    gtk_init (&argc, &argv);
    window = SetupWindow("Tournament", "images/Midway_Madness_Shell.jpg");
    g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);

    frame = gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(window), frame);

    btnSpin = gtk_button_new_with_label("Spin");
    gtk_widget_set_size_request(btnSpin, 70, 40);
    gtk_fixed_put(GTK_FIXED(frame), btnSpin, 720, 540);
    g_signal_connect(G_OBJECT( btnSpin ), "clicked", G_CALLBACK(btnSpin_clicked), NULL );

    btnExit = gtk_button_new_with_label("Exit");
    gtk_widget_set_size_request(btnExit, 70, 40);
    gtk_fixed_put(GTK_FIXED(frame), btnExit, 595, 540);
    g_signal_connect(G_OBJECT( btnExit ), "clicked", G_CALLBACK(btnExit_clicked), NULL );

    DoSpin( &egm );
    DisplaySymbols( &egm );

    gtk_widget_show_all(window);
    gtk_main ();
    return( 0 );
}

GTK2オブジェクトの定義を提供しているように見えるドキュメントから読んだものを適用する方法を理解するのに苦労しているので、この問題を解決する方法の詳細な説明といくつかのサンプルコードに非常に感謝しますそして関数呼び出し。非常に徹底的な対応が必要な場合は、見事な報奨金を提供できます。

すべてのコードがあると便利な場合は、ここで提供します。

編集:メモリリークは2つの方法で修正されました。

  1. nobarGtkFixedによって提案されたように、イメージを再描画する前に、コンテナーを破棄して再作成します。
  2. ポインタの2次元配列を使用しGtkWidgetて、描画時に各画像へのポインタを保持します。画像を再描画するときは、2次元配列のウィジェットポインタが最初に次のように破棄されます。

    int ReleaseImages(void){u_int8_t y、x;

    /* release images */
    for( y = 0; y < 3; y++ )
    {
        for( x = 0; x < 5; x++ )
        {
            gtk_widget_destroy( ptrImages[y][x] );
        }
    }
    return( 0 );
    

    }

    これで、画像リソースが解放され、新しい画像を再描画できます。

4

1 に答える 1

3

GtkFixedのドキュメントから:

ほとんどのアプリケーションでは、このコンテナを使用しないでください。他のGTK+コンテナーについて学ぶ必要はありませんが、アプリケーションが壊れてしまいます。GtkFixedを使用すると、次のことが原因で、テキストが切り捨てられたり、ウィジェットが重複したり、その他の表示バグが発生したりします...

上記の引用から重複するウィジェットを強調したいと思います。アプリケーションの実行を継続すると、GtkFixedコンテナにさらに多くのイメージを追加し続けます。コンテナから画像を削除することは決してないため、画像が表示されなくなっても、画像には引き続きメモリが必要です。

細かく言うと、古い画像が見えないのは、新しい画像で覆ってしまったからです。GtkFixedウィジェットに関する限り、アプリケーションの開始以降に追加したすべての画像はまだそこにあります。

これを修正するには、古い画像を削除する必要があります。これを行うには多くの方法があります。最も簡単なのはコンテナ全体を破棄することかもしれませんが、ボタンもそのコンテナに配置するため、いくつかの問題があります。

より良い解決策は、おそらく上記の引用からのアドバイスに従い、GtkFixedを使用しないことです-または少なくともアプリケーションをレイヤー化して、GtkFixedが画像にのみ使用されるようにします(ボタンをGtkFixedの外に配置できます)。ただし、前述のように、これには他のGTK +コンテナーについて学習する必要がある場合があります(最初のGtkFixedコンテナーがボタンと2番目のコンテナーの両方を保持しているときに、 2番目のGtkFixedコンテナーを使用して画像を保持する場合を除く)。

于 2012-08-01T06:11:06.350 に答える