今天的 Tetralet 又在唧唧喳喳了



« 四月 2017 »
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30






 

Gtk+2 元件的記憶體用量

Tetralet | 03 七月, 2008 01:26

如果您是用 ThunderBird 來收發電子郵件的話,您可能會注意到一個有趣的現象:不管您執行了多次 ThunderBird,系統並不會因而開出多個 ThunderBird 視窗。ThunderBird 在啟動時的同時似乎會進行什麼自我偵測機制,以避免系統上因同時存在多個 ThunderBird 行程而導致無謂得浪費寶貴系統資源。

支援這種機制的軟體有個專有名詞叫『Single-Instance Application (感謝 caleb 提供資訊)』,相對於一般軟體則是以『Separate Process』的模式執行。因此,個人把這種機制叫做『Single Process (暫)』。

LilyTerm 已於 0.9.4 版開始支援 Single Process。此後,不管執行多少次 LilyTerm,新的 LilyTerm 將只是由第 1 個 LilyTerm 所分出來的新視窗。如果您用 ps 指令來查看的話,您會發現系統裡將只有 1 個 LilyTerm 行程。這也就是為什麼個人把它做 Single Process 的原因。

舉例來說,在個人的電腦上,一個新開啟的 LilyTerm 行程將會佔用掉約 9MB 的記憶體:

$ ps aux | grep lilyterm
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
tetralet  2531  0.8  1.7  30220  9164 pts/1    S    00:01   0:00 lilyterm
但改為使用 Single Process 後,另一個新開啟的 LilyTerm 行程將只會多佔用 172KB
$ ps aux | grep lilyterm
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

tetralet  2531  0.2  1.8  30268  9336 pts/1    S    00:01   0:00 lilyterm

也就是說,原本一個新開啟的 LilyTerm 行程應該是會再額外佔用 9MB 的記憶體,啟用了 Single Process 機制後一下子減少到只需 172KB!這真的是太驚人了。世界上所有軟體應該把 Single Process 機制列為標準備配才是。

但是,天底下真的有那麼好的事情嗎?

應用程式的記憶體佔用量

首先,如果您查看一下,您會發現 LilyTerm 的 0.9.4 版的執行檔大小約為 76KB,但載入到了記憶體裡就變成了 9MB。我想您應該猜得到,這是因為 LilyTerm 在載入記憶體的同時,也會同時載入像是 libclibXft libgtklibvte 等等函式庫的關係。您可以利用 ldd 指令來查看 lilyterm 會連結到哪些函式庫。
註:
其實新開啟的 LilyTerm 行程並不會佔用到那麼多記憶體。使用 ps 指令並不能精確得指出應用程式實際的記憶體使用量。後文將有說明。

另外,下文中所有的測試數據和您系統所安裝的 字型/輸入法/編譯 方式都有很大關係,所以在您的電腦上數據也許會有一些小出入。
但人們的想法裡,程式在載入記憶體後,會先展開,然後把一堆函式庫抓進來,這也是為什麼明明只有 76KBLilyTerm 在載入到了記憶體裡就變成了 9MB 的主要原因。也就是說,執行檔越大、函式庫連結越多的應用程式,應該會佔用較多的記憶體。

但讓我們看看下面的例子。如果您用 ldd 指令來查看 evilvtelilyterm 這兩個極相似的程式的話,您會發現兩者會連結到的函式庫並沒有什麼分別,但載到記憶體的結果卻大異其趣:
$ ls -l
-rwxr-xr-x 1 root root 76284 2008-07-01 19:10 /usr/bin/lilyterm
-rwxr-xr-x 1 root root 28636 2008-05-28 17:24 /usr/bin/evilvte


$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

tetralet  2550  0.8  2.1  54988 11240 pts/1    S    00:01   0:00 evilvte

tetralet  2531  0.8  1.7  30220  9164 pts/1    S    00:01   0:00 lilyterm
LilyTerm 的執行檔大小約為 evilvte 的 3 倍,也比 evilvte 提供了更多功能,所以 evilvte 理論上應該比較輕巧才是,但載入記憶體後 evilvte 卻比 LilyTerm 佔用了更多的記憶體。為什麼?這並不合理呀?

Gtk+2 應用程式的記憶體使用狀況

也許我們利用另一個 vte based 的 X Terminal Emulator - xfce4-terminal 來說明會比較清楚。以下為使用不同參數來啟動 xfce4-terminal 的結果:
$ ps aux | grep xfce4-terminal
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

tetralet  2512  0.7  2.4  56480 12732 pts/1    S    00:01   0:00 xfce4-terminal
tetralet  2603  1.0  2.0  31572 10696 pts/1    S    00:03   0:00 xfce4-terminal --hide-toolbars --hide-menubar
在將 toolbar 及 menubar 隱藏起來後,xfce4-terminal 所佔用的記憶體明顯變少了 - 甚至比 evilvte 還小。也就是說,GNU/Linux 在載入 Gtk+2 應用程式時,並不是一股腦得把函式庫裡的所有元件全載進來:只有實際有使用到的元件才會被載入,這的確是相當聰明有彈性的做法。

因此,我們可以猜到:evilvte 預設會顯示 statusbar,這也就是它比 LilyTerm/xfce4-terminal 佔用更多記憶體的主因。GNU/Linux 的應用程式並不是執行檔小,它就會佔用較少的記憶體,一切都要看實際的狀況而定。

libvte 癡肥?

以下是一個極簡版的 Gtk 應用程式。除了一個單一視窗外什麼都沒有:
#include <gtk/gtk.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);

        GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        g_signal_connect (G_OBJECT(window), "delete_event",
                          G_CALLBACK(gtk_main_quit), NULL);
        gtk_widget_show_all(window);
        gtk_main();
        return 0;
}

這個 gtk_demo 程式在載入後約佔用 4.2MB 的記憶體:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
tetralet  2627  0.0  0.8  12320  4232 pts/1    S    00:05   0:00 ./gtk_demo
然後,利用以下程式碼,我們就可以大略估算出:如果再多載入單一 vte 元件,將會比 gtk_demo 再多佔用掉約 3.8MB 的記憶體:
#include <vte/vte.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);

        GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        g_signal_connect (G_OBJECT(window), "delete_event",
                          G_CALLBACK(gtk_main_quit), NULL);
        GtkWidget *vte = vte_terminal_new();
        vte_terminal_fork_command(VTE_TERMINAL(vte), NULL, NULL,
                                  NULL, NULL, TRUE, TRUE, TRUE);

        gtk_container_add(GTK_CONTAINER(window), vte);
        gtk_widget_show_all(window);
        gtk_main();
        return 0;
}

做為對照組,如果再多載入單一 gtk_entry 元件(Gtk 的輸入欄位元件)後,將會比 gtk_demo 再多佔用掉約 3.4MB 的記憶體:
#include <gtk/gtk.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);

        GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        g_signal_connect (G_OBJECT(window), "delete_event",
                          G_CALLBACK(gtk_main_quit), NULL);
        GtkWidget *entry = gtk_entry_new();
        gtk_container_add(GTK_CONTAINER(window), entry);
        gtk_widget_show_all(window);
        gtk_main();
        return 0;
}

以上的程式其實際執行結果如下:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
tetralet  2627  0.0  0.8  12320  4232 pts/1    S    00:05   0:00 ./gtk_demo

tetralet  2667  0.8  1.5  38164  7828 pts/1    S    00:05   0:00 ./entry_demo

tetralet  2648  0.4  1.5  29532  8068 pts/1    S    00:05   0:00 ./vte_demo
也就是說,若單看記憶體用量的話,載入一個像 vte 那麼複雜的元件也等同載入一個 entry 元件再多一點點而己。請別忘了,比起 entry_demo 來,vte_demo 可還多載入了一個 libvte.so.9 函式庫呢!也就是說,光以記憶體用量來說,或許 libvte 會比 gtk_entry 元件更為輕巧呢!libvte 癡肥?個人認為是有點苛刻了。

Gtk+2 元件的記憶體使用機制

看到這裡您可能會很訝異:載入 1 個 gtk_entry 元件會佔用掉約 3.4MB 的記憶體。那麼一個設計稍微複雜的應用程式,將會佔用掉多少的記憶體?那未免太誇張了吧?

我們不妨來試驗一下。以下是一個裡面放了 100gtk_entry 元件的單一視窗:
#include <gtk/gtk.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);
        int i;

        GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        g_signal_connect (G_OBJECT(window), "delete_event",
                          G_CALLBACK(gtk_main_quit), NULL);
        GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
        for (i=0;i<100;i++)
        {
                GtkWidget *entry = gtk_entry_new();
                gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 0);
        }

        gtk_container_add(GTK_CONTAINER(window), vbox);
        gtk_widget_show_all(window);
        gtk_main();
        return 0;
}
我們比較在一個視窗裡放入了 1 個及 100 個 gtk_entry 元件看執行後會佔用的記憶體會是多少:
$ ps aux | grep entry_demo
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

tetralet  2667  0.8  1.5  38164  7828 pts/1    S    00:05   0:00 ./entry_demo
tetralet  2668  2.0  1.5  38412  8068 pts/1    S    00:05   0:00 ./entry_demo_100
結論是,就算多了 99 個 gtk_entry 元件,記憶體用量只多增加了 240KB,平均起來也只是約 2.4KB。也就是說,Linux 不但會視情況載入必要的元件,且 Gtk+ 的元件之間還會相互分享記憶體

模擬 Single Process 的情形?

那麼,我們模擬在 Single Process 的狀況下,一次會呼叫出 100 個視窗會怎麼樣?
#include <gtk/gtk.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);
        int i;

        for (i=0;i<100;i++)
        {
                GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
                g_signal_connect (G_OBJECT(window), "delete_event",
                                  G_CALLBACK(gtk_main_quit), NULL);
                GtkWidget *entry = gtk_entry_new();
                gtk_container_add(GTK_CONTAINER(window), entry);
                gtk_widget_show_all(window);
        }

        gtk_main();
        return 0;
}
結果如下:
$ ps aux | grep entry_demo
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

tetralet  2667  0.8  1.5  38164  7828 pts/1    S    00:05   0:00 ./entry_demo
tetralet  2668  2.0  1.5  38412  8068 pts/1    S    00:05   0:00 ./entry_demo_100
tetralet  2669  4.4  1.6  38948  8584 pts/1    S    00:05   0:01 ./entry_demo_100_window
結論是,就算是一次叫出 100 個視窗,只比原本的單一視窗多出了 756KB 的記憶體。Gtk+ 的元件就算是在多視窗之下還是會相互分享記憶體。

Single Process vs. Separate Process

那麼,讓我們比較一下 Single Process 和 Separate Process 之間的差異吧!以下是會以單一 Process 產生 100 獨立 vte 視窗的程式:
#include <vte/vte.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);
        int i;

        for (i=0;i<100;i++)
        {
                GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
                g_signal_connect (G_OBJECT(window), "delete_event",
                                  G_CALLBACK(gtk_main_quit), NULL);
                GtkWidget *vte = vte_terminal_new();
                vte_terminal_fork_command(VTE_TERMINAL(vte), NULL, NULL,
                                          NULL, NULL, TRUE, TRUE, TRUE);
                gtk_container_add(GTK_CONTAINER(window), vte);
                gtk_widget_show_all(window);
        }
        gtk_main();
        return 0;
}

以下是其記憶體使用量前後比較表:
             total       used       free     shared    buffers     cached
Mem:        515596     111572     404024          0       5648      49588
-/+ buffers/cache:      56336     459260
Swap:       431824          0     431824

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
tetralet  2559  1.0  2.2  33216 11544 pts/1    S    00:40   0:05 ./vte_demo_100
tetralet  3050  0.0  0.5   5388  2780 pts/33   Ss+  00:41   0:00 /bin/bash x 100

             total       used       free     shared    buffers     cached
Mem:        515596     316172     199424          0       8020      52060
-/+ buffers/cache:     256092     259504
Swap:       431824          0     431824
我們可以看到,這個程式執行後約略會吃掉 188MB 的記憶體,且十之八九都是被 bash 給佔用掉的,因為 vte_demo_100 本身只佔用了 11MB 的記憶體。

然後,我們用以下的指令跑看看一次跑 100 個獨立的 vte_demo,看看會佔用掉多少的記憶體:
$ perl -e 'system("./vte_demo&") for (1...100);'
其結果如下:
             total       used       free     shared    buffers     cached
Mem:        515596     111820     403776          0       5896      49588
-/+ buffers/cache:      56336     459260
Swap:       431824          0     431824

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
4411 tetralet  17   0 29536 8060 5996 S  0.0  1.6   0:00.16 vte_demo x 100
tetralet  3050  0.0  0.5   5388  2780 pts/33   Ss+  00:41   0:00 /bin/bash x 100

             total       used       free     shared    buffers     cached
Mem:        515596     505120      10476          0      10796      52048
-/+ buffers/cache:     442276      73320
Swap:       431824          0     431824
雖然用 free 指令並不是很精確的估算方式,畢竟系統又不是只在跑這一隻程式。但我們大略可以看出來,跑 100 個獨立的 entry_demo 會佔用掉約 385MB 的記憶體,若再扣掉 bash 所佔用掉的 188MB 的記憶體,我們可以估算出來 entry_demo 約莫是一個 Process 佔用 2MB 的記憶體。雖然比原本的 8MB x 100 節省了不少,但遠不如 Single Process 的 100 個視窗只佔用掉 11MB 的記憶體來得節省。

也就是說,在各個 Seperate process 之間也是會相互分享記憶體,但其效益遠不如 Single Process 來得大。

Gtk+2 不同的元件間的記憶體使用機制

您可能會很好奇:那麼 gtk_entryvte 是不是也會相互分享記憶體呢?讓我們用以下程式測試一下吧:
#include <vte/vte.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);

        GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        g_signal_connect (G_OBJECT(window), "delete_event",
                          G_CALLBACK(gtk_main_quit), NULL);
        GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
        GtkWidget *entry = gtk_entry_new();
        gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 0);
        GtkWidget *vte = vte_terminal_new();
        vte_terminal_fork_command(VTE_TERMINAL(vte), NULL, NULL,
                                  NULL, NULL, TRUE, TRUE, TRUE);

        gtk_box_pack_start(GTK_BOX(vbox), vte, TRUE, TRUE, 0);
        gtk_container_add(GTK_CONTAINER(window), vbox);
        gtk_widget_show_all(window);
        gtk_main();
        return 0;
}
結果如下:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
tetralet  2627  0.0  0.8  12320  4232 pts/1    S    00:05   0:00 ./gtk_demo
tetralet  2667  0.8  1.5  38164  7828 pts/1    S    00:05   0:00 ./entry_demo
tetralet  2648  0.4  1.5  29532  8068 pts/1    S    00:05   0:00 ./vte_demo
tetralet  2628  0.7  1.9  54464 10272 pts/1    S    00:05   0:00 ./gtk_demo_vte+entry
也就是說,Gtk+2 就算是不同元件之前也是會相互分享記憶體!這實在太驚人了。

Linux 的記憶體分配方式

最後,筆者想提一下的是 Linux 記憶體分配方式。請參考以下程式:
#include <gtk/gtk.h>

int main( int   argc,
          char *argv[])
{
        gtk_init (&argc, &argv);

        GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        g_signal_connect (G_OBJECT(window), "delete_event",
                          G_CALLBACK(gtk_main_quit), NULL);
        gtk_widget_show_all(window);
        gpointer mem = g_malloc0(100*1024*1024);
        gtk_main();
        return 0;
}
我們跟系統要了 100MB 的空白記憶體。這時您可能會心想:如果多跑幾隻類似的惡搞程式,系統的記憶體很快就不夠用了。但實際執行結果如下:
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
tetralet  2627  0.0  0.8  12320  4232 pts/1    S    00:05   0:00 ./gtk_demo
tetralet  2647  0.1  0.8 114724  4236 pts/1    S    00:05   0:00 ./mem_demo
在上例中,雖然 mem_demogtk_demo 多要求了 100MB 的記憶體,但最後 mem_demo 實際上只比 gtk_demo 多佔用了 4K 的記憶體。我們可以猜到的是:Linux 不管應用程式請求了多少記憶體,它只有在必要時才會真的把記憶體分配給應用程式。這也就是 Linux 記憶體管理十分了不起的地方。

LilyTerm vs. evilvte vs. xterm vs. urxvt vs. mlterm 小比較

因此,或許我們可以再替 Gtk+2 平反一下。

個人的 X 預設是開了 6 個虛擬桌面,習慣上每個桌面會擺一個 LilyTerm 在跑。若假設每個 LilyTerm 都開啟了 2 個分頁,我就一共開了 12 個 Terminal 在跑了。因此,敝人就想拿幾個常用的 X Terminal Emulator 測測看在此情況下,它們的記憶體使用量了: 

支援
分頁
Single
Process
執行檔大小
測試方式 行程大小
測試結果
LilyTerm

76KB
2 分頁 x 5 視窗 11,804K x  1
21,228K
xterm

319KB
10 視窗
2,836K x 10
22,804K
mlterm 291KB
2 Pty x 5 視窗 6,384K x  5
27,676K
urxvt
1,226KB
2 分頁 x 5 視窗 6,372K x  5
27,964K
evilvte
28KB
2 分頁 x 5 視窗 11,552K x  5
35,532K
vte_demo
4KB
10 視窗 8,228K x 10
38,600K
註: 測試環境:Celeron 850 + RAM 512MB。
全數使用程式預設值
mlterm 可用 <Ctrl><F1> 來開啟一個新的 Pty 視窗。
其中,xterm 真的是驚人的輕巧,但由於 LilyTerm 支援了 Single Process,所以在此情況下還是能略勝 xterm 一籌。但 vte_demo 則由於既不支援分頁也不支援 Single Process 只好敬陪未座了。

我們可以發現,Gtk+2 based 的應用程式的確會佔用比較多的記憶體空間,也容易給人不夠輕巧的負面觀感。但考慮到 Gtk+2 對於多國語系、輸入法、字型、以及它提供了程式設計師更簡易的設計方式,那麼 Gtk+2 會不夠輕巧也是情有可原的。如果有人嫌 Gtk+2 不夠輕巧,所以重新開發具有相同特性(多國語系、字型、輸入法、佈景主題、元件眾多、易學易用…等等)的 TooKit,能設計得比 Gtk+2 更輕巧嗎?個人卓實抱持著保留的態度。

反過來說,既然 xterm 那麼輕巧,那麼 LilyTerm 就一無是處了嗎?個人的答案也是抱持著保留的態度。
我們可以看到:Gtk+2 的程式設計師只要加把勁,其實也可以將程式設計到和最輕巧的程式一較上下。

我想人們在選擇應用軟體時應該不會只考慮到程式是否夠輕巧,其它像是穩定度、功能、介面、操作習慣…都是考慮的要素之一。個人並不認為在 xterm 之前,LilyTerm/mlterm/ urxvt 就會失去了它的競爭力。

Single Process 真的是一種可行的方式!

由以上測試得知,一些像是 X Terminal Emulator 之類我們可能會開多個視窗的應用程式,的確是應該支援 Single Process,它對節省記憶體所帶來的效益可以說是立竿見影。如果您想挑選順手的 X Terminal Emulator,個人認為應該要把 Single Process 納入考量,它的確是個殺手級的功能!

不過,Single Process 也並不是百利無害  -  如果其中一個視窗當掉了,那麼該 Process 下的所有視窗將會隨之崩潰。也就是說,支援 Single Process 至少本身要夠穩定才行,否則效果將會是適得其反 - 這也是看到支援 Single Process 的程式的同時所該慎重得納入考量的地方。
迴響

以上的推測,其實有很多不正確的地方

Tetralet 前輩,關於 GTK+ 部份,你推測出的結論其實有不少問題
述小弟直言,其實,大部分都不正確。

1. 要了解 GTK+ 程式的記憶體使用情形,應該先閱讀 GObject 系統的程式碼。 你看到得很多並不是 Linux 的設計,是 GObject 動態物件系統本身有 cache 的設計。又因為 C 語言無法支援物件,所以他為了模擬,大部分的資料是在 runtime 才產生,所以耗用的空間會隨程式複雜度長大。單看程式啟動第一次的記憶體消耗是不準的。

2. GtkEntry 載入時,會連上層所有的 parent class 以及整個 GTK+ lib 做初始化。GTK+/Glib 內部有相當大量 Lazy initialization 的設計,所以這解釋了你看到的行為,這根元件之間是否刻意設計成共用是無關的。另外,關於某些共享的部份,是現代作業系統本身的功能,code section 本來就會共享,甚至某些作業系統有 COW 處理。記憶體用量也不一定是真正的用量,某些系統會在 page fault 的時候才進行真正的配置,所以這樣的測量方式,其實不正確。相關細節太過複雜,無法在此詳述,建議有機會可以閱讀 GTK+ 程式碼,應該會對這些測試的結果有些全然不同的想法。

3. 在 GtkEntry 啟動時,這部份程式碼我沒仔細讀,但是個人推測,其實還啟動了 IM engine 的部份,所以不是這個元件特別大。

4. X 程式有分 server side 和 client side,程式在 runtime 並不是所有資源用量都在你程式的空間裡面,事實上有一部分在 X 裡面,所以,這樣的測量方式,其實是誤差非常大的。

5. VTE 為了改善效能不彰的問題,在內部有做大量的 cache 動作,資源消耗量會在用一段時間之後逐漸增加,只有剛啟動的空視窗,當然看不出。在只有空視窗的時候,他就跟一般的 widget 沒兩樣。 詳細細節,請閱讀 VTE 程式碼,這個動作尤其出現在使用 xft backend 的時候。另外,你如果有常識讀過 VTE 程式碼,應該就會了解為何他會比較肥大。 裡面有非常多複雜的處理在處理所謂的複雜文字和 RTL。這部份在 urxvt 和 xterm... 等等,是完全沒有支援的,加上 xterm 使用的字型處理方式不同,所以拿這個來說 xterm 輕巧,其實是很不正確的,這和說 dillo 比 firefox 輕巧一樣,功能差一截,其實不能在同一個基礎上比較。

6. 關於 toolkit 的部份,比 gtk+ 效率更好並且提供更多功能的 lib,在 Windows 上面非常多,又根據某些實際的 benchmark,Qt4 的效能在很多方面是明顯勝過 GTK+ 2,但是很多人因為缺乏對技術細節的了解,只一味堅持 C++ 程式不可能比 C 快的荒謬觀念,也不願意深入了解其中的細節,更是拒絕進行實際的測試,導致一些成見,長久以來深植人心。這部份,建議有機會可以嘗試 Windows 下的 GUI 開發,應該就可以明顯感受到 GTK+ 的不足之處。

[回應] PCMan @ 03/07/2008, 02:27

期待一個更好的Gtk+

GTK+是目前我在Linux有用到的GUI Toolkit裡面,I18N作最好的了,可惜,如PCMAN大說一般,實在是有慢的感覺:有時連要叫出個print 的dailog都要等上四秒以上,而我這台電腦是今年才買的。

我幾乎每天都要靠Gtk才能工作:用Evolution收發信件、排行程、整理連絡資訊;用Gnucash記帳;用Firefox看網頁;用Eclipse寫程式,用Pidgin作即時通訊;用Gimp、Dia和Inkscape畫圖(流程圖或一些基礎美工),用F-spot整理圖檔.....等等。

這幾年來,我幾乎每天都會遇到一些Gtk的問題(開Dialog非常慢等一類的效能問題,或應該說是X window system的綜合問題),到了今天,我幾乎變成習慣了,覺得Gtk的東西本來就是如此。

為什麼要用Gtk+based的application?我覺得是因為前一段時間 qt3-based 的kde3在I18N上的表現不如Gtk+(2)based 的吧,
有時用konqueror(qt3 based)看wikipedia, 一堆非西歐字元都會變方塊(例如天城文),這點konqeuror就在Gtk+2 based的Firefox給打死了,連進入到比較效能的第二回合的機會都沒有。

現在Qt4出現了,甚而可以跟Gtk+的應用程式及環境整合,這是令人很高興的事,相信會給Gtk+的開發團隊一些驅力去增進Gtk+。

[回應] Gtk+使用中 @ 03/07/2008, 13:20

Re: PCMan

敝人認為,您一開頭就下『其實有很多不正確的地方』是滿不禮貌的行文風格。

1. 若以上面的 mem_demo 程式而言,一直等到日後它真的要用到那 100MB 記憶體時,系統才會真的分配給實體記憶體給它。這並不是 Gtk+2 程式才有的特性。您可以寫隻程式驗証看看就可以知道。

2. 關於應用程式和記憶體真正的用量,敝人文中已不斷強調:ps 的結果和 free 的結果是不相符的,但 ps 的結果卻是極具參考性的指標。ps 指令的 RSS 欄位代表的是該單一行程所引用的『所有實體記憶體』,其中當然包含了它和別的行程所共用的共享函式庫。我想,如果您能先弄清楚 ps 的結果及它所代表的意義,或許您在此就會有不同的看法了。

3. 請試試 gtk_label,它應該不會外掛 IM engine,但它的記憶體用量和 gtk_entry 相差無幾。

4. 請先想想 ps 的輸出結果代表什麼意思再下此評論,好嗎?ps 在前文中已有說明。

5. 文中也說了,因為 Gtk+2/VTE 特意加強對多國語系的支援,所以會不夠輕巧。但這並不會影響 LilyTerm 的競爭力。敝人仍然覺得 VTE 實在是個了不起的專案。

6. 敝人不願在此掀起 Gtk+ vs. QT 的戰火。QT 的惡劣形象其來有自 - 包括對多國語系的支援、字型、輸入法… 反而 QT 是 C 還是 C++ 卻在其次。

若提到啟動速度,您不妨在 IceWM/EvilWM 這類非 Gtk+/Qt 環境下同時開啟 konsole 及 gnome-terminal,就可以有深刻了解了。Qt 也許不比 Gtk+ 慢,(個人實測結果速度其實也不差),但很多時候 qt 是受到 KDE 的惡劣形象所拖累。很多事是眼見為憑的。

另外,您提到了 Win32 的 Toolkits 很多比 Gtk+2 更優良,這種事個人卻認為是 case by case 的。比如說,敝人曾在 Win32 下開發過 wxWidgets 程式,因為 Visual C++ 無法滿足敝人的需求。我可以因此斷定說 wxWidgets 比較優良、Visual C++ 只是垃圾嗎?恐怕會給人一種『以偏蓋全』的不良印象吧?

[回應] Tetralet @ 03/07/2008, 15:53

你還是沒有看懂

無意筆戰,上文的確是不太禮貌,抱歉,
我只是單純想討論技術,請真的仔細看我到底寫了什麼
先不用太激動,我也沒有要跟你討論 LilyTerm,
這裡是針對 GTK+ 的技術討論。

1. 我已經說過了,GTK+ 有很多 lazy loading / caching 的設計,請你先閱讀GTK+2 和 GObject 程式碼,因為我們在講的可能是完全不一樣的事情。你講的行為是每個程式都有,
但 GTK+ 除了這個以外,還有許多額外的設計,
會讓這樣的現象更加明顯。但你上文,把作業系統的功能
和 GTK+ 2的設計混淆,這樣是不正確的。
我在強調一次,你先不要急著反駁,我不是要來筆戰的。
請你先閱讀GTK+程式碼,這樣我們才能針對「同一件事情」討論
因為他的很多設計,真的不是像你推測的這樣。

2.大家都知道 ps 和 free 不相符,但是我跟你強調過了
在 X 下的程式有許多的資源消耗量並不能夠這樣看出來。
因為有很大一部份的資源消耗在 X 裡面,所以單靠 ps
來估計,誤差會非常大,因此減損了他在這裡的參考價值。
建議,應該同步考慮在 X 裡面的部分。

3. IM 只是我的推測,但扣掉這些,gtk+2 / pango 就根我
前面說的一樣,完全是 lazy initilization pattern 的設計
所以 GTK+ 裡面大部分的東西,會在建立第一個 widget 的時候
進行載入,所以才會造成你看到的狀況。至於 GtkLabel,
他並不是一個輕巧的 widget,事實上他的功能很複雜
(不信,讀過程式碼你就會發現了,他是外觀簡單,內部
複雜的 widget,記得要連上層的 parent class 一起讀)。
如果你在第一個 widget 建立,然後顯示視窗之後,做個按鈕
在按下按鈕的時候,才開始建立上千個 label/entry widgets,
然後再用這樣大量統計出的結果去平均,我想應該可以部分去除
gtk+ 本身 lazy initilization 的影響,或許這樣比較會更有趣

4. 請你先看懂我前面在寫什麼,不要這麼激動。
你可以先去讀 GTK+/GObject source code,然後跟我的論點參照
如果有不對的地方你可以指正,我很樂意討論。

5.我沒有要跟你討論 LilyTerm,LilyTerm 當然是個好程式
但是這裡是在討論 GTK+。很多人拿 KDE 程式的缺陷
來說是 Qt 的問題,我想 Qt 也太倒楣了一點。
Qt 本身是非常優秀的 lib,慢的是 KDE,不是 Qt。

6. wxWidgets 是摹仿 MFC 為其基礎架構,很多設計和
現代化的開發工具相差甚多。建議你可試試看 Delphi/VCL
wxWidgets 在 Windows 下,並不是第一線的解決方案,
當需要跨平台的時候,他很好用,但一般使用下,有更多
很好用的「商業產品」。當然,如果要 free 的,那就會少一些
另外... wxWidgets 是可以搭配 VC++ 使用的,這兩個是
完全不同的東西,你拿IDE 比較 toolkit,
這樣會變張飛打岳飛。 MFC/SDK 當然是很難用,但是 VC++
本身是很好用的 IDE。MFC 難用是當然的,
它是沿習 Win 3.1時代的設計,介面是包裝比他更古早的 SDK。
但是,除了這個,比他好用的還多著,雖然幾乎都是商業產品。

[回應] PCMan @ 03/07/2008, 19:47

關鍵是demand paged ?

討論串有比較到process或lib執行時吃記憶體的情況

demand paged簡單的說就是kernel只載入保證會用到的page到記憶體裡,所以一支process可能需要非常大的記憶體,但是kernel不會同時一次就分配給它,可能程式執行到某部份,這部份還躺在disk(可能是指令也可能是資料),這時就發生page fault,然後把需要的page載入

問題是為啥有的process或lib一開始執行時只吃一點點記憶體,有的卻吃很多

我想有的process或lib一開始執行時就向kernel要較多的記憶體(在demand paged原則下還是要的到)

有的是只要一點點記憶體,日後需要再慢慢跟kernel拿

兩者差別是,一開始要求多的可以拿去當cache,要求少的日後page fault次數就多了自然會影響效能

以上是我猜的

神奇的記憶體管理方法demand paged似乎是從4.2BSD就實作出來,之後的出產作業系統就都有這功能,但是不一會用

[回應] asd2063 @ 03/07/2008, 19:55

Re: Gtk+使用中

我不清楚在您的電腦上跑 Linux 為什麼會慢到那種地步... 我的 NB 已經買了近 6 年了,但就算跑起 xfce4+Compiz 基本上還可以。

個人認為,請您先檢查記憶體 - 512MB 算最基本配備了。另外請用 hdparm -Tt /dev/hda 來檢查您的硬碟速度。以下是敝人管理的 Server 的成績:

Timing cached reads: 860 MB in 2.00 seconds = 429.30 MB/sec
Timing buffered disk reads: 232 MB in 3.00 seconds = 77.22 MB/sec

若您的 Linux 還是很慢,換用其它較輕量級的 DE,像是 XFce4 或是 IceWM,應該會發現其決定性的不同。

BTW, 個人使用的印表系統是 CUPS。並沒有像您說的慢到那種地步呀?

[回應] Tetralet @ 04/07/2008, 14:01

Re: PCMan

看來我們的爭論是在 ps 指令的結果的可信度。請您使用 pmap 指令和 ps 指令的結果比較看看,或許可以了解 ps 指令所輸出的結果的依據何在了。

[回應] Tetralet @ 04/07/2008, 14:40

Re:

這沒什麼好爭論的吧...

若說 lazy initialize
single process vs separate process
都會是 lazy initialize

難不成 separate or single 的行為就不一樣??

OS 對於 single vs separate process 的處理本來就不完全相同

這應該是 Tetralet 要表示的吧??

[回應] dou0228 @ 08/07/2008, 22:14

偷偷把記憶體吃掉

Tetralet:
請先了解 ps 指令輸出的結果包涵了記憶體使用狀況

PCMan:
請先了解 GTK+ 程式碼才能正確判斷記憶體使用量

這...到底要先了解那個?
PCMan 似乎暗示 GTK+ 程式碼有使用偷吃步?所以 ps 是不準的,是這樣嗎?

[回應] 偷偷地 @ 09/07/2008, 10:10

ps vs /proc/pid/status

#include
int main(void)
{
int *p = (int *)malloc(1000000 * 100);
sleep(1000);
return 0;
}

要走約 100MB 的記憶體, 但 *p 並未被設值

free or ps 看的 MEM% 不正確
但 ps 裡的 VSZ 是正確的

VmPeak: 99080 kB
VmSize: 99080 kB
...
VmData: 97688 kB
...

若程式本身另外寫 memory management
這不管 single or separate process 都會是一樣的

[回應] dou0228 @ 09/07/2008, 12:11

Re: dou0228

在 ps 所顯示的資訊裡,VSZ 指的是『程式向系統要求的記憶體大小』,而 RSS 則是『系統實際配備給該程式的記憶體大小』。

其中,RSS 的記憶體大小則包含了共用函式庫的大小,但因為可能有多個程式同時指向了同一份共用函式庫,因此會被重覆計算。所以在文中,個人已強調過:RSS 的值只對『單一程序』有意義,若以整個系統來看的話,RSS 的值會被高估了。

而不管 Gtk+2 內部有什麼機制,RSS 的資訊應該不會就因此有誤。個人認為這應該沒什麼好爭辯的?

另外,top/ps 裡所看到的 MEM% 是用 RSS 來計算的,所以加總起來後會大於 free 所給的資訊。free 的資訊則應該是正確的,但用 free 會看不出來單一程序在記憶體中實際所佔用的記憶體大小。

[回應] Tetralet @ 09/07/2008, 17:14

Re:

沒錯, 基本上就很簡單
不管 GTK+ 程式怎麼寫, 也不管 OS 怎麼處理

基本上 single process 一定比 separate process 吃的資源要來的少

所以, 若 GTK+ 做了 trick, 那也沒差, ps, free, os 看不到也無所謂

因為站在都是基於GTK+ base 的程式基礎上

free 基本上是沒問題, 只不過, 若只是 declare not define
就不會被列在裡頭

[回應] dou0228 @ 09/07/2008, 18:07

插個話

第一點:
Tetralet 你講到
"Linux 不管應用程式請求了多少記憶體,它只有在必要時才會真的把記憶體分配給應用程式",也強調RSS是真正OS配給process 用的memory,我想這是大家都認同。
但是我認為PCMan 想講的是說gtk 中有用到他所說的 lazy initialization 的機制,應該是有很多物件,記體原本要和系統要的,gtk 都假裝不知道,可能你要動動視窗,還是跟其元件交互動作一下才會被初始,那這些memory就不會在程式初啟時被算入RSS。所以pcman 說到
"所以耗用的空間會隨程式複雜度長大。單看程式啟動第一次的記憶體消耗是不準的"

第二點:
Tetralet 你有拿gtk_entry 和vte 比,並這樣的結論
"光以記憶體用量來說,或許 libvte 會比 gtk_entry 元件更為輕巧呢"
你的假設是不是gtk_entry 這麼一個簡單的元件,應該不會耗費太多資源才是?如果這個假設是錯誤的那上述的結論就不成立啦。pcman 也提到gtk_entry(他寫gtk_label 應該是筆誤)其實是一個非常複雜的元件,如果這為真,那vte就一點也不輕巧啦。

同步一下大家觀點,沒別的意思,火氣不要這麼大

[回應] softpapa @ 11/07/2008, 19:15

Re: softpapa

本文的主題便是在講記憶體(函式庫)的共用,以及 ps 指令中的 RSS 及 VSZ 欄位的差別。個人認為用『程式啟動第一次的記憶體消耗』來當作例子應該是極為恰當的。

否則,又要考慮到使用者可能做了什麼操作,又要考慮到共用函式庫可能帶來的影響,如此一來變數太多,那更是作不得準了。

另外,PCMan 所提到的 gtk_label 並不是筆誤哦∼請再把 PCMan 的意見再看一次。也就是說,若說 vte 肥的話,那麼沒幾個 gtk 元件可以算瘦的了... XD

[回應] Tetralet @ 11/07/2008, 21:50

我們始終在雞同鴨講

1. GtkEntry 真的很複雜,你以為他只是簡單的小 widget?
http://svn.gnome.org/viewvc/gtk%2B/trunk/gtk/gtkentry.c?view=markup
自己看,光這一個小 GtkEntry 的程式碼,已經比你整個 LilyTerm 還要多了一千行。而且 GtkEntry 部份的功能在 GtkEditable...等等其他 class 內。
GtkLabel 的程式碼有將近五千行,即使他在螢幕上只秀一行字。
GtkEntry 本來就不是一個輕巧的元件,他只是看起來很小。
大部分的 gtk+ 元件,的確是不瘦沒有錯,我從來就不覺得 gtk+ 很輕巧,尤其是和 Windows 的 GUI 系統來比,但是論彈性就是 gtk+ 勝,有得必有失。

2. gtk+ 的設計是,記憶體一律等到真的要用的時候才配置。所以你第一次建立第一個 entry widget 的時候,同時載入了很多除了 entry 以外的東西,那並不是單一 entry 的用量。同理,這樣估算 VTE 也不準確。你應該重複建立大量 widgets,然後再來估算平均,設法扣掉第一個 widget 建立時造成的 initilization,會比較準。

3. 所有視窗資源、一些圖片...等等,記憶體空間是吃在 X 的 process 內,不是你的程式,這塊從 ps 完全看不到,但這塊其實還不少,所以我說估算不準,那不是 ps 正確與否的問題,而是那些資源根本不是吃在你的程式 process 內,ps 根本不會算到,需要用 X 相關工具查詢。

4. 我已經說過了,VTE 的記憶體用量是隨使用時間增加會增長。你一開始只開了空的 VTE 視窗當然是沒吃到什麼。那個視窗在還是空的時候,除了把背景塗成黑色,什麼事情都沒做,這樣當然是不會吃到什麼 RAM。你要考慮實際日常使用的情況。而且基本上在換頁,捲動的時候,CPU 使用率會明顯往上衝,而且會拖慢 console 程式的執行速度,用 konsole 等其他終端機則完全沒有這種現象。不信用 konsole 跑有大量畫面捲動的 console 程式,就知道差在哪裡。

5. 你 LilyTerm 分頁標籤會搶走焦點的問題,試試這個。
GTK_WIDGET_UNSET_FLAGS( notebook, GTK_CAN_FOCUS );

我就回到這裡,不繼續回了,參考資料已附上。
先前如有不禮貌很抱歉,純討論技術議題,並非存心踢館。

[回應] PCMan @ 12/07/2008, 02:43

Re: PCMan

但個人卻認為您似乎陷入了意氣之爭了?

1. 我的原文是『光以記憶體用量來說,或許 libvte 會比 gtk_entry 元件更為輕巧呢!』,您似乎是會錯意過度引申為『gtk_entry 非常輕巧』了。

2. 您提到了,『gtk+ 的設計是,記憶體一律等到真的要用的時候才配置。』,而我原文中也同樣寫了『Linux 不管應用程式請求了多少記憶體,它只有在必要時才會真的把記憶體分配給應用程式。』,還寫了個小範例程式以供驗証。那麼請問您到底在爭論什麼呢?

3. X 本來就是 Client/Server 架構,也就是說 X Client 和 X Server 的行為本來就是分開的,硬要把 X Server 的東西算在 X Client 的頭上其實並不合理。

4. 首先,應用程式常常會隨著使用者的操作而使用越來越多的記憶體,個人認為這種可想而知的事應該是沒什麼好爭論的。接下來,雖然說比較一下載入一些文字後的記憶體變化其實也蠻有趣的,但若真要比較,是不是也得在 gtk_entry 塞滿東西才算公平不是嗎?但如此比較結果又有什麼意義?所以在文中當然沒有進行這類的比較了。

5. 非常感謝您提供的資訊!這個問題將於 LilyTerm 0.9.6 中修正!

[回應] Tetralet @ 12/07/2008, 22:12

還是回一下好了

1. 因為這個結論不一定正確,理由我前面都講過了。
2. 因為除了作業系統本身,gtk+ 額外有做很多處理。你看到的有很大一部分是 gtk+ 的特殊處理,那部份根本不是 Linux 做的。我在講的是這個。
3. 如果今天我寫個程式,拼命建視窗,拼命建 pixmap,在 X 裡面花了一堆資源,實際上會造成系統資源吃重,然後程式本身沒用到什麼 RAM,我可否稱我的程式為輕巧?扣除 X 的部份對 GUI app 並不合理。
4. 我的確是認為應該測試塞滿文字之後的比較,真正使用的情況,沒人會維持這些視窗元件在空白的情況。在視窗是空的時候,除了把視窗塗黑其他事情都不用做,所以很多真正需要的記憶體,也都沒有配置,你要怎麼比較記憶體用量?只有把視窗塗黑根本用不了什麼資源,這時候不管什麼 widget 都是一樣的。
比較嚴謹的測試方式,個人推薦:建立 gtk+ window 之後,在上面建一個 entry 和 vte,這樣兩者都初始化完畢了。接著,分別在兩個程式各建立 1000 個 entry 和 vte,然後在裡面填入一樣的文字,比較增加的使用量。這樣應該就可以扣除其他因素。

[回應] PCMan @ 13/07/2008, 04:02

R: PCMan,無聊的意氣之爭

1. 我的原文是『光以記憶體用量來說,或許 libvte 會比 gtk_entry 元件更為輕巧呢!』,您可以把 libvte.so.9 編進 entry_demo 看看就可以知道所言非虛。

2. 何不看看 dou0228 所提供的小範例程式?眼見為憑。

3. 我們是在比『元件大小』,而不是在比『元件內含物』大小,請問您能否分辨其中的差別?

4. 同上。Gtk+2 各元件的立足點本來就不一致了,如果再加上一堆不確定的變因下去不是讓結果更不精確了嗎?

比如說,我要比較 Firefox 和 IE 的記憶體使用量。如果我又讓 IE 在 wine 下面跑,又讓 Firefox 掛了一堆 Extentions,然後載入的 Flash Plugin 版本又不同,那請問如此比較結果有意義嗎?

[回應] Tetralet @ 13/07/2008, 13:02

這樣才有意義

舉例:
你今天要比較兩廠牌 A 車和 B 車,哪一台省油
你可以只有把兩台車發動,然後停在停車場
然後得出 A 比 B 省油的結論嗎?

開出去跑當然耗油就會變多,而且
開到路上去跑當然是會多出很多變因,
但是那才是有意義的比較。

應該被比較的是真正的 use case
而我提供的方式就是讓你去除那些變因的。

如果照你提出的說法,
你要比較兩個瀏覽器記憶體用量,你是會開兩個瀏覽器
讓他們都只開 about:blank 來比較嗎?
還是你要算誰連結的 dll 比較多?

不要鬧了...
當然是比較實際開啟網頁的使用情況,這樣才有意義。
大家都有陳述自己論點的權利,不論意見是否相同
我有很清楚的說明理由了,也有附上我根據的參考資料來源
你不接受,我也沒辦法,不過這並不是意氣之爭
我跟你沒什麼恩怨過節,也沒什麼好爭的。
一切答案都在 source code 裡,寫得很清楚了。

另外幫你之前寫的 gtk+ 教學補個勘誤
處理按鈕順序不需要那麼複雜,請直接用:
gtk_dialog_set_alternative_button_order()
用法詳見 gtk+ API doc及 gtk+ source code.

[回應] PCMan @ 13/07/2008, 14:35

Re: PCMan

1. 引喻失義。車子發動後隨著時間流逝,油一定會越耗越多。Gtk 元件可沒有這種特性。另外,也不乏有人在斤斤計較『怠速時的油耗』問題。您舉的例子其實並不恰當。

2. gtkentry 和 vte 可以說是完全不同的元件,幾乎沒有共通點,因此說什麼要載入一些東西來比較是蠻無意義的。就像您用 AutoCAD 開了某個 DWG 文件,然後又用 PhotoShop 開了另一個 PSD 文件,然後下結論說:『PhotoShop 的記憶體用量較省』,這種比較方式不是很荒謬嗎?

3. 您以瀏覽器作例子也不是很恰當,gtkentry 和 vte 又不是提供了相同功能的元件。把一段文字貼進去 gtkentry 等同於把一段文字貼進去 vte 嗎?

4. 好,就依您的說法測了一下。在 demo_entry 及 vte_demo 裡都放上了千字文 (含註解),用 free 檢驗的結果為 demo_entry 的 3164K,對照 vte 是 3136K (別忘了扣掉 bash 1004K)。好了,我可以得到『光以記憶體用量來說,libvte 的確是比 gtk_entry 元件更為輕巧』這個結論了嗎?

5. 還什麼『不要鬧了』勒。再看看您之前的發言,您和人討論事情一定得用這種語氣?

6. gtk_dialog_set_alternative_button_order() 乃是適用於 GtkDialog,不太好套用到我那個範例程式裡。我那個範例程式主要是用 GtkWindow。

[回應] Tetralet @ 14/07/2008, 15:35

果然是有趣的測試

我也寫了自己的測試程式:

#include
#include

int main( int argc, char* argv[] )
{
int i;
char* data;
gsize len;

gtk_init( &argc, &argv );
GtkWidget* win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget* box = gtk_vbox_new(FALSE, 0);

GtkWidget* term = vte_terminal_new();
GtkWidget* entry = gtk_entry_new();
GtkWidget* scroll = gtk_scrolled_window_new( NULL, NULL );
gtk_scrolled_window_add_with_viewport( scroll, box );
gtk_box_pack_start( box, term, FALSE, TRUE, 0 );
gtk_box_pack_start( box, entry, FALSE, TRUE, 0 );

g_file_get_contents( argv[2], &data, &len, NULL );
for( i = 0; i < 20; ++i )
{
GtkWidget* w;
if( argv[1][0] == 'v' )
{
w = vte_terminal_new();
vte_terminal_feed( w, data, len );
}
else
{
w = gtk_entry_new();
gtk_entry_set_text( w, data );
}
gtk_box_pack_start( box, w, FALSE, TRUE, 0 );
}
g_free(data);

gtk_container_add( win, scroll );
gtk_window_maximize( win );
gtk_widget_show_all( win );
g_signal_connect(win, "delete-event", gtk_main_quit, NULL);

gtk_main();
return 0;
}

沒用到 bash,是直接灌資料進 vte。所有 widget 全部顯示。

我這邊的測試結果很有趣:
當視窗數很少 ( 5 ~ 10 ),文字資料量也少的時候,
我的測試結果跟你的一樣,vte 用量的確如你所說,是真的比較少。

但是當我開始把視窗數量調高,並且改用比較大量的文字資料後,vte 的用量就開始攀升,不過有趣的是,攀升的幅度的確沒有我預期的大。

在大量文字資料的情況下 (符合真實使用環境),vte 的用量我這邊測試比 entry 多,但是並沒有多很多。加上實際使用環境下不會開那麼多 vte,所以我想這部份可以支持到你的結論,vte 的確沒有比 GtkEntry 多消耗多少。 不過有趣的是,當我把數字都開到很大的時候 ( > 1000 ),entry 測試變得很慢,但是還會動,而 vte 則是一直狂吃我的 swap,然後我就當機了,完全啟動不了。

當然,這樣的測試對 vte 並不公平,因為實際上沒有這種使用情境,不過這個現象很弔詭。從 vte source code 我一時也看不出大量的情況下用量會攀升的理由,畢竟測試資料都固定,該 cache 的應該都 cache 了,不會再增加那部份的資料。

不過,我只測試了英文資料,不確定在其他複雜多國語言的情況下,表現會如何。純英文的話,兩者的用量,的確是接近,差異在可接受範圍內。

經過測試,這部份我贊成你的結論。嘖嘖...沒想到 GtkEntry 耗用的比我想像得要更多...

另外,我一開始會回這篇的理由是,你的測試方式看起來 ok,但是那些數據並不足以得出你後面所寫的那些結論,加上你把一些 gtk+ 內部的設計和 Linux 的行為混在一起,那是我主要回文的理由。

離題了,回到原題,single instance 的程式,對桌面來說的確是不錯的方式,我也很愛用,這部份和你意見是一致的。

[回應] PCMan @ 14/07/2008, 20:29

design pattern

這算是某種Design Pattern. 這個pattern 的名稱 叫
Singleton. 主要是用來避免 無謂的 mem allocation.

[回應] neo @ 03/08/2008, 10:26

Re: Gtk+2 元件的記憶體用量

我这里lilyterm初始开一个窗口就40mb的RES,实在有点恐怖,相比较urxvt开一个窗口只要10mb的RES。

[回應] seenxu @ 31/01/2009, 23:31

Re:

补充一下,我这里用的是ubuntu 8.10, amd64

[回應] seenxu @ 31/01/2009, 23:32

Re: seenxu

若用 top 看一個程式『實際』佔用了多少記憶體,是以 SHR 欄位為準,看 RES 並不準。RES 指的是應用程式『號稱』它已佔用多少記憶體。

另外,vte based 的 X Terminal Emulator 都很肥,那是沒辨法的事。印象沒錯的話,LilyTerm 已經是其中最 lightweight 的了。要不是 urxvt 對於 tab / single instance 的支援度並不是那麼好,其實個人會推薦人們使用 urxvt 的說。

改天來寫一個『X Terminal Emulator 大比較』好了。

[回應] Tetralet @ 01/02/2009, 00:26

authimage
驗證碼皆為英文大寫字母
僅輸入前4碼即可。後2碼是假的,欺敵用。
這是為了防制 Spam 而設計的。若造成您的不便還請見諒!
Accessible and Valid XHTML 1.0 Strict and CSS
Powered by LifeType - Design by BalearWeb