新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 教你輕松控制uClinux 嵌入式開發過程

        教你輕松控制uClinux 嵌入式開發過程

        作者: 時間:2012-04-19 來源:網絡 收藏

        恰當的內存分配

          除了提供跟普通Linux一樣的內存分配器之外,還提供另一個可選的。普通Linux中缺省的內存分配器是使用“2的冪”的分配方法,這樣可以快速找到符合要求的內存區域。不幸的是,在下這種方法可能會帶來令人痛苦的結果。

          為了理解這一問題帶來的結果,尤其是大的內存分配,我們舉例說明。試想一個應用程序要求33KB的內存空間進行裝載。如果使用“2的冪”的分配方法,就必須分配64KB(2的6次方)內存空間,多余的31KB內存空間不能被利用上。在中,這種浪費是不能接受的。為了解決這個問題,專門為 uClinux內核設計了可選的內存分配器。不同的內核版本,這個可選的內存分配器不同,一般是page_alloc2和kmalloc2。

          page_alloc2能解決缺省的分配方法造成的浪費問題。雖然它也是使用“2的冪”的分配方法,但它是按頁(每頁4096字節,即4KB)分配的,分配的內存大小如果已經滿足了要求,則只是將當前的一頁分配出去,其它的就不再分配。在前面的例子中,如果使用這種方法,就只是分配36KB (≥33KB,且為整頁)即可,這樣就能節省28KB的空間。

          page_alloc2還采取了一些避免內存碎片的方法。它將所有的兩頁(8KB)或更少的內存需求從空閑內存開始部分向上分配,所有大的內存需求從剩余內存的末尾部分開始向下分配。這樣防止了網絡緩存等的臨時分配,避免了內存碎片的出現。

          一旦開發者理解了內核內存分配的區別,應用程序中就會出現變化。

          1.沒有動態棧的問題

          在使用虛擬內存的Linux上,當一個應用程序試圖沖銷棧頂單元時,會被標記異常,同時系統會映射新的內存到棧頂以便讓棧增長。在 uClinux下,由于必須在編譯階段給棧分配好內存,所以不會有這樣的增長。當出現莫名其妙的崩潰或者新移植的應用程序出現怪異行為時,開發者首先應該考慮到的是給棧分配的內存大小問題。缺省情況下,uClinux為棧分配4KB的內存空間,開發者可以用下面提到的方法之一來增加棧的空間。

         ◆ 應用程序build之前

          應用程序build之前,可以在Makefile文件中增加以下兩行代碼:

          FLTFLAGS = -s

          export FLTFLAGS

          ◆ 應用程序build之后

          應用程序build之后,可以運行以下命令:

          flthdr -s executable

          其中,stacksize 就是為棧增加的內存空間。

          2.沒有動態堆的問題

          堆是C語言中malloc及相關函數分配內存的區域。在有虛擬內存的Linux上,應用程序可能通過動態堆在運行過程中改變進程的大小。這個功能是通過在底層使用sbrk()和brk()系統調用來實現的。sbrk()是在進程的末尾增加內存空間,所以調用sbrk()能夠使應用程序獲得額外的內存。

          brk()可以把任意位置設置為進程空間的末尾,因此,可以通過調用brk()減少或增加內存空間的占用。由于uClinux不能實現brk()和sbrk(),它采用了一個全局的內存池,就是內核的空閑內存池。使用全局內存池的方法有一些優點。

          首先,此方法只會給進程分配使用時真正需要的內存。其次,內存用完后就會被歸還給全局內存池,而且可以利用已經存在的內核中的分配器來分配內存,這樣可以減少應用程序的代碼量。但這個方法是有缺陷的,比如,一個失控的進程可以用完系統全部的可用內存。

          新手普遍會遇到丟失內存的問題。系統會顯示大量的可用內存,但是應用程序卻不能得到。這正是由于內存碎片的存在,uClinux幾乎不可能完全利用內存,現有的解決方法中都存在這個問題。這個問題可用一個例子很好地說明。

          假設一個系統有500KB的空閑內存,為了裝載一個應用程序需要分配100KB的空間。大家可能覺得這個需要肯定能得到滿足,然而,應該知道,必須有 100KB連續的內存空間才能滿足這個需要。如果有500KB的空閑空間,但是最大的連續內存塊的大小只有80KB,這樣是沒有辦法分配給這個應用程序的。造成這種情況有很多原因。上面講到的page_alloc2內核分配器有一個配置選項可以用來識別這個問題,在內核源代碼page_alloc2.c 文件中可以獲得更多的信息。

          經常有人會問為什么不能進行內存的碎片整理,以便實現剛才的例子中的要求?原因是uClinux沒有虛擬內存,所以不能移動程序正在使用的內存。在使用虛擬內存的情況下,只要重新定位就能實現內存的移動,從而實現內存碎片的整理。

          在沒有虛擬內存的情況下,由于程序經常會引用已經分配給它的內存區域,這樣,如果移動程序的內存,程序就會崩潰。在uClinux下,現在還沒有解決這個問題的辦法。開發者需要自己注意這個問題,如果有可能的話,盡量使用小的內存塊。

          掌控進程和應用程序

          1.進程

          有虛擬內存的Linux和uClinux的另一個區別在于后者沒有fork()系統調用。這就要求開發者在移植時對使用了fork()的應用程序做一些工作。uClinux下惟一的選擇是使用vfork()。盡管vfork()與fork()有很多共同點,但是它們之間的區別影響很大。

          對于不熟悉fork()和vfork()的人來說,這兩個系統調用都是允許將一個進程分裂成一個父進程和一個子進程。當一個進程調用 fork()時,子進程是父進程的一個完全拷貝,但是它不共享父進程的任何東西,并且能夠單獨執行,就和父進程一樣。vfork()調用就不同了,首先,父進程被掛起直到子進程調用exec(),或者子進程退出才能繼續。

          由此可見,這個系統調用是用來啟動一個新的應用程序。其次,子進程在vfork()返回后直接運行在父進程的??臻g,并使用父進程的內存和數據。這意味著子進程可能破壞父進程的數據結構或棧,造成失敗。

          為了避免這些問題,需要確保一旦調用vfork(),子進程就不從當前的棧框架中返回,并且如果子進程改變了父進程的數據結構就不能調用exit函數。子進程還必須避免改變全局數據結構或全局變量中的任何信息,因為這些改變都有可能使父進程不能繼續。



        關鍵詞: uClinux 嵌入式開發

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 张家川| 益阳市| 香格里拉县| 佛冈县| 中方县| 长子县| 武穴市| 土默特左旗| 德格县| 广灵县| 全椒县| 措美县| 康乐县| 新营市| 化隆| 聂拉木县| 高台县| 曲水县| 祁门县| 克东县| 古交市| 灵台县| 宁都县| 武清区| 蓬溪县| 逊克县| 桂林市| 佳木斯市| 景宁| 抚州市| 论坛| 东阿县| 肥乡县| 池州市| 毕节市| 柏乡县| 衡水市| 通州区| 临泉县| 竹山县| 惠来县|