為什麼一個MessageBox都要佔用18M內存?

一直沒發現我寫了純API的程序居然佔用了18M內存,一開始是懷疑是我程序的問題,後來逐步的刪減,直到寫成

#include &

int __stdcall wWinMain(hndl ist,hndl hpi,wchar *cl,int cs) {

MessageBox(0,L"s",L"s",0);

return 0;

}

還是18M內存.

編譯環境為GCC+MingW.

然後我又測試了Delphi的程序.

這個是劉麻子的用Delphi改寫的Programming Windows 5的例子,HelloMsg

program HelloMsg;

uses Windows; // 引用此單元,以便調用常用的Win32 API函數

begin

MessageBox (0, "Hello, Windows 98!", "HelloMsg", 0);

end.

也是18M.

然後我翻出了,原版的Programming Windows 5的HelloMsg,直接運行Release下的exe,還是18M.

有時候運氣好,可能是12M.

18M內存,是指在window任務管理器"內存使用"一項顯示的值.

有誰知道是為什麼?


開始以為問的是編譯後尺寸的問題,仔細看一下才明白是運行內存的佔用。

以題主的這個MessageBox為例,如果是在32位環境下,它在內存的布局大概是這樣的(與編譯器版本相關):

[主線程棧],8頁,32KB

[保護頁],1頁,4KB

[代碼段],1頁,4KB

[rdata段],1頁,4KB

[data段],1頁,4KB

[const段],1頁,4KB

[共享DLL區],與DLL大小相關

題主你看到的16MB內存大部分是被共享DLL區佔用了。

這裡包括兩大塊:

一塊是系統的標準庫ntdll、kernel、gdi32等,保證了你能夠在屏幕上建立窗口(包括繪圖)、響應滑鼠事件等操作,這些庫大部分都是必需的,如果移除他們,代碼可能無法執行。這部分在我的環境里大概佔用2-3MB的內存,我這裡的這個「最小」MessageBox程序佔用內存約5MB

另一塊是vccrt相關的,包括初始化線程棧等動作,這些其實可以手動完成,但vc要想直接生成不帶CRT的二進位代碼還是有難度的。

如果希望代碼佔用的內存儘可能少,應該怎麼辦:

1. 儘可能減少對共享庫的依賴,能在命令行輸出,就不要用圖形界面,這樣gdi32里的很多東西就用不上了;

2. 壓縮主線程棧,減少不用的segment,這需要調整編譯器才能實現;

3. 不用標準的CRT,自己實現一套CRT庫。

另外,雖然表面上這個exe佔用了很多內存,實際上由於DLL是共享的,如果有多個進程同時使用一個相同的DLL,那麼這個DLL在物理內存中,只存在1份,並不額外消耗物理內存。


你知道這些api是需要載入很多系統的庫的么?你可以用Dependency Walker這個工具查看你載入了哪些動態庫。


你以為大小是功能的正比例函數

其實應該是一次函數(在簡單場景下)


你試試用tcc編譯,你就會發現編譯連接之後大小遠遠超出你的想像。

那麼你為什麼不從編譯環境去找問題呢?

有些編譯環境會默認把系統的一些庫載入進去,而且你還用的是GCC?

或者換一個思路,程序讀取你的可執行文件,用標準的可執行文件格式去分析裡面到底有哪些填充物。

一個最簡單的WIN32程序我記得最小就10幾K,真的。

分析過程請參考《程序員的自我修養》


推薦閱讀:

在 n 個整數里,找出2個數相加等於 sum 的所有整數?
WPF是可行的C++程序GUI解決方案么?
如何提高C++編程能力,以及為將來找工作做準備?
後台linux c/c++大型項目開發中 在windows下 大家一般用什麼工具編輯調試比較順手?
為什麼不給Python 這樣的解釋語言寫一個編譯器?

TAG:MicrosoftWindows | C |