<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          操作系統(tǒng)就用一張大表管理內(nèi)存?

          共 2491字,需瀏覽 5分鐘

           ·

          2021-12-27 11:58

          今天我們不聊具體內(nèi)存管理的算法,我們就來看看,操作系統(tǒng)用什么樣的一張表,達(dá)到了管理內(nèi)存的效果。


          我們以 Linux 0.11 源碼為例,發(fā)現(xiàn)進(jìn)入內(nèi)核的 main 函數(shù)后不久,有這樣一坨代碼。

          void?main(void)?{
          ????...
          ????memory_end?=?(1<<20)?+?(EXT_MEM_K<<10);
          ????memory_end?&=?0xfffff000;
          ????if?(memory_end?>?16*1024*1024)
          ????????memory_end?=?16*1024*1024;
          ????if?(memory_end?>?12*1024*1024)?
          ????????buffer_memory_end?=?4*1024*1024;
          ????else?if?(memory_end?>?6*1024*1024)
          ????????buffer_memory_end?=?2*1024*1024;
          ????else
          ????????buffer_memory_end?=?1*1024*1024;
          ????main_memory_start?=?buffer_memory_end;

          ????mem_init(main_memory_start,memory_end);
          ????...
          }

          除了最后一行外,前面的那一大坨的作用很簡單。


          其實就只是針對不同的內(nèi)存大小,設(shè)置不同的邊界值罷了,為了理解它,我們完全沒必要考慮這么周全,就假設(shè)總內(nèi)存一共就?8M?大小吧。

          ?

          那么如果內(nèi)存為 8M 大小,memory_end?就是

          8 * 1024 * 1024

          也就只會走倒數(shù)第二個分支,那么?buffer_memory_end?就為

          2 * 1024 * 1024

          那么?main_memory_start?也為

          2 * 1024 * 1024

          ?

          你仔細(xì)看看代碼邏輯,看是不是這樣?


          當(dāng)然,你不愿意細(xì)想也沒關(guān)系,上述代碼執(zhí)行后,就是如下效果而已。

          ?

          ?

          你看,其實就是定了三個箭頭所指向的地址的三個邊界變量。具體主內(nèi)存區(qū)是如何管理和分配的,要看 mem_init 里做了什么。

          void?main(void)?{
          ????...
          ????mem_init(main_memory_start,?memory_end);
          ????...
          }

          而緩沖區(qū)是如何管理和分配的,就要看再后面的 buffer_init 里干了什么。

          void?main(void)?{
          ????...
          ????buffer_init(buffer_memory_end);
          ????...
          }

          不過我們今天只看,主內(nèi)存是如何管理的,很簡單,放輕松。


          進(jìn)入 mem_init 函數(shù)。

          #define?LOW_MEM?0x100000
          #define?PAGING_MEMORY?(15*1024*1024)
          #define?PAGING_PAGES?(PAGING_MEMORY>>12)
          #define?MAP_NR(addr)?(((addr)-LOW_MEM)>>12)
          #define?USED?100

          static?long?HIGH_MEMORY?
          =?0;
          static?unsigned?char?mem_map[PAGING_PAGES]?=?{?0,?};

          //?start_mem?=?2?*?1024?*?1024
          //?end_mem?=?8?*?1024?*?1024
          void?mem_init(long?start_mem,?long?end_mem)
          {
          ????int?i;
          ????HIGH_MEMORY?=?end_mem;
          ????for?(i=0?;?i????????mem_map[i]?=?USED;
          ????i?=?MAP_NR(start_mem);
          ????end_mem?-=?start_mem;
          ????end_mem?>>=?12;
          ????while?(end_mem-->0)
          ????????mem_map[i++]=0;
          }

          發(fā)現(xiàn)也沒幾行,而且并沒有更深的方法調(diào)用,看來是個好欺負(fù)的方法。

          ?

          仔細(xì)一看這個方法,其實折騰來折騰去,就是給一個 mem_map 數(shù)組的各個位置上賦了值,而且顯示全部賦值為 USED 也就是 100,然后對其中一部分又賦值為了 0。

          ?

          賦值為 100 的部分就是 USED,也就表示內(nèi)存被占用,如果再具體說是占用了 100 次,這個之后再說。剩下賦值為 0 的部分就表示未被使用,也即使用次數(shù)為零。


          不是很簡單?就是準(zhǔn)備了一個表,記錄了哪些內(nèi)存被占用了,哪些內(nèi)存沒被占用。這就是所謂的“管理”,并沒有那么神乎其神。

          ?

          那接下來自然有兩個問題,每個元素表示占用和未占用,這個表示的范圍是多大?初始化時哪些地方是占用的,哪些地方又是未占用的?


          還是一張圖就看明白了,我們?nèi)匀患僭O(shè)內(nèi)存總共只有 8M。

          ?

          ?

          可以看出,初始化完成后,其實就是 mem_map 這個數(shù)組的每個元素都代表一個 4K 內(nèi)存是否空閑(準(zhǔn)確說是使用次數(shù))。


          4K 內(nèi)存通常叫做 1 頁內(nèi)存,而這種管理方式叫分頁管理,就是把內(nèi)存分成一頁一頁(4K)的單位去管理。

          ?

          1M 以下的內(nèi)存這個數(shù)組干脆沒有記錄,這里的內(nèi)存是無需管理的,或者換個說法是無權(quán)管理的,也就是沒有權(quán)利申請和釋放,因為這個區(qū)域是內(nèi)核代碼所在的地方,不能被“污染”。

          ?

          1M 到 2M 這個區(qū)間是緩沖區(qū),2M 是緩沖區(qū)的末端,緩沖區(qū)的開始在哪里之后再說,這些地方不是主內(nèi)存區(qū)域,因此直接標(biāo)記為 USED,產(chǎn)生的效果就是無法再被分配了。

          ?

          2M 以上的空間是主內(nèi)存區(qū)域,而主內(nèi)存目前沒有任何程序申請,所以初始化時統(tǒng)統(tǒng)都是零,未來等著應(yīng)用程序去申請和釋放這里的內(nèi)存資源。


          那應(yīng)用程序如何申請內(nèi)存呢?我們本講不展開,不過我們簡單展望一下,看看申請內(nèi)存的過程中,是如何使用 mem_map 這個結(jié)構(gòu)的。


          memory.c 文件中有個函數(shù) get_free_page(),用于在主內(nèi)存區(qū)中申請一頁空閑內(nèi)存頁,并返回物理內(nèi)存頁的起始地址。


          比如我們在 fork 子進(jìn)程的時候,會調(diào)用 copy_process 函數(shù)來復(fù)制進(jìn)程的結(jié)構(gòu)信息,其中有一個步驟就是要申請一頁內(nèi)存,用于存放進(jìn)程結(jié)構(gòu)信息 task_struct。

          int?copy_process(...)?{
          ????struct?task_struct?*p;
          ????...
          ????p?=?(struct?task_struct?*)?get_free_page();
          ????...
          }

          我們看 get_free_page 的具體實現(xiàn),是內(nèi)聯(lián)匯編代碼,看不懂不要緊,注意它里面就有 mem_map?結(jié)構(gòu)的使用。

          unsigned?long?get_free_page(void)?{
          ????register?unsigned?long?__res?asm("ax");
          ????__asm__(
          ????????"std?;?repne?;?scasb\n\t"
          ????????"jne?1f\n\t"
          ????????"movb?$1,1(%%edi)\n\t"
          ????????"sall?$12,%%ecx\n\t"
          ????????"addl?%2,%%ecx\n\t"
          ????????"movl?%%ecx,%%edx\n\t"
          ????????"movl?$1024,%%ecx\n\t"
          ????????"leal?4092(%%edx),%%edi\n\t"
          ????????"rep?;?stosl\n\t"
          ????????"movl?%%edx,%%eax\n"
          ????????"1:"
          ????????:"=a"?(__res)
          ????????:"0"?(0),"i"?(LOW_MEM),"c"?(PAGING_PAGES),
          ????????"D"?(mem_map?+?PAGING_PAGES-1)
          ????????:"di","cx","dx");
          ????return?__res;
          }

          就是選擇 mem_map 中首個空閑頁面,并標(biāo)記為已使用。


          好了,本講就這么多,只是填寫了一張大表而已,簡單吧?之后的內(nèi)存申請與釋放等騷操作,統(tǒng)統(tǒng)是跟著張大表 mem_map 打交道而已,你一定要記住它哦。



          ------



          本文可以當(dāng)做?你管這破玩意叫操作系統(tǒng)源碼 系列文章的第 13 回。

          為了讓不追更系列的讀者也能很方便閱讀并學(xué)到東西,我把它改造成了單獨的不依賴系列上下文的文章,具體原因可以看?堅持不下去了...

          點擊下方的閱讀原文可以跳轉(zhuǎn)到本系列的 GitHub 頁,那里也有完整目錄和規(guī)劃,以及一些輔助的資料,歡迎提出各種問題。
          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产三级电影久久 | 免费在线看片黄在线观看 | 欧美精品成人一区 | 日本一级A片 | 久久狼友 |