“你定義了那么多全局變量,系統才給你分配了幾百KB,這樣做是不是太耗內存了?”,一同學問道。
老早就聽說嵌入式系統各種資源有限啊,不能分配大空間啊要注意節約資源之類的(。。。貌似米神4的配置要完爆我的thinkpad了。。。)。那是不是全局變量的使用真的會占用很大系統內存,而系統真的才分配幾百KB空間給我呢?
我不信,所以我要嘗試一下:
全局變量,肯定是要占用內存的,但無論是不是全局變量,只要是已定義的變量都會占用內存,這個和是否是全局的沒啥關系,只是占用的區域不一樣而已(詳見APUE存儲器安排 P153)。
系統怎么可能就給我幾百K的空間,那我的安卓機上的QQ咋動不動就幾十兆的資源占用率?
不扯淡了,下面就是我的探究內容。
獲得當前進程的堆棧的最大字節長度 :
#define getLimit(name) get_limits(#name,name)//這個#是字符串創建符,可以在宏中創建字符串//只是打印判斷是具體數值還是字符串void PRint_infinite(rlim_t t){ if(RLIM_INFINITY == t) { printf("%14s ","infinite"); } else { printf("%14ld ",t/1024/1024); }}//封裝了獲取特定類型數據的最大值static void get_limits(char *name,int resource){ struct rlimit limit; if(getrlimit(resource,&limit) != 0) { printf("get limit error %s/n",strerror(errno)); } printf("%-14s ",name); print_infinite(limit.rlim_cur); print_infinite(limit.rlim_max); putchar('/n');}//入口函數,得到進程的堆棧最大值void GetProcessHeapAndStackLimitSize(){ printf(PARTING_LINE); printf("%-14s ","Name"); printf("%13s ","LimCur(MB)"); printf("%13s /n","LimMax(MB)"); //RLIMIT_DATA 數據段的最大字節長度: 初始化數據、非初始化及堆的總和 getLimit(RLIMIT_DATA); //RLIMIT_STACK 棧區的最大字節長度 getLimit(RLIMIT_STACK); printf("/n");}用來測試獲取數據是否正確的一個小方法:
遞歸調用,每調用一次消耗系統 棧區 大小1M。自動變量以及每次函數調用時所需保存的信息都放在棧區。
//用來測試,是否是堆的最大值void GetStackSize(){ static int i = 1; char xxx[1024*1024] ;///1MB printf("now i is : %d/n",i); GetStackSize(++i);}寫個main函數,先調用GET方法,獲得堆棧值再調用測試函數結果如下:
=============================== GetProcessHeapAndStackLimitSize ================================= Name LimCur(MB) LimMax(MB) RLIMIT_DATA infinite infinite RLIMIT_STACK 8 infinite now i is : 1now i is : 2now i is : 3now i is : 4now i is : 5now i is : 6now i is : 7Segmentation fault (core dumped)
infinite可以理解為不限制,從結果可以看出,當前進程的堆區(其實,這種方法獲得的不是嚴格意義上的堆區,這里獲得的是包括初始化數據、非初始化數據及堆區的總和)的大小是
沒有限制的,而棧區系統卻僅僅分配了8M的空間,也就是說,當前進程下你能使用的局部變量等總和不能超過8M,否則系統就會出現錯誤(Segmentation Fault)。
如果果真如此的話,那我在main函數里直接定義char xxx[8*1024*1024]會是什么情況呢?顯然的,什么都不執行就段錯誤了。
8M顯然是不夠我用的,特別是當我需要各種緩沖區時,那我該如何“擴容”呢?或者我系統確實內存有限不能讓某些應用程序占用過多內存,那么我如何限制它的內存使用呢?
下面就是修改系統 默認配置的方法:
//封裝了設置特定類型數據的最大值static void set_limits(char *name,int resource,rlim_t cur,rlim_t max){ struct rlimit limit; limit.rlim_cur = cur; limit.rlim_max = max; if(setrlimit(resource,&limit) != 0) { printf("get limit error %s/n",strerror(errno)); } else { printf("%s %s OK /n",__func__,name); }}void SetProcessHeapAndStackLimitSize(){ printf(PARTING_LINE); //RLIMIT_DATA 數據段的最大字節長度: 初始化數據、非初始化及堆的總和 rlim_t pref = 10*1024*1024; setLimit(RLIMIT_DATA,pref,pref*2); //RLIMIT_STACK 棧區的最大字節長度 setLimit(RLIMIT_STACK,pref*2,pref*4); }這樣設置的結果會什么什么樣子呢?我們可以先設置之,然后再重新調用GET方法看看是否設置成功。
//主函數int main(int argc ,char **argv){ GetProcessHeapAndStackLimitSize(); //GetStackSize();//沒有重新設置之前,返回7就崩潰了 SetProcessHeapAndStackLimitSize(); GetProcessHeapAndStackLimitSize(); GetStackSize();//設置后,返回19就崩潰了 ruturn 0;}結果如下:
=============================== GetProcessHeapAndStackLimitSize ================================= Name LimCur(MB) LimMax(MB) RLIMIT_DATA infinite infinite RLIMIT_STACK 8 infinite =============================== SetProcessHeapAndStackLimitSize ================================= set_limits RLIMIT_DATA OK set_limits RLIMIT_STACK OK =============================== GetProcessHeapAndStackLimitSize ================================= Name LimCur(MB) LimMax(MB) RLIMIT_DATA 10 20 RLIMIT_STACK 20 40 now i is : 1now i is : 2now i is : 3now i is : 4now i is : 5now i is : 6now i is : 7now i is : 8now i is : 9now i is : 10now i is : 11now i is : 12now i is : 13now i is : 14now i is : 15now i is : 16now i is : 17now i is : 18now i is : 19Segmentation fault (core dumped)
恰如我們所料,修改參數成功,我們可以使用更多的棧區,也可以限制堆區的使用。
而當我們多次執行時卻發現一個有趣的現象:雖然我們設置成功了,但重新運行程序后,系統還是會僅僅給我們分配8M,可見我們的這個改變僅僅是對當前進程的設置生效,那么如何對系統所有生效呢?見下文分解。
了解這些東西之后,我們有時可能會碰到程序無故掛掉,任何error信息都不打印,甚至GDB都不說問題出在哪里時,大伙可能得考慮一下,是否被系統限制了。
源碼已上傳。
新聞熱點
疑難解答