歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux0.11內存管理

linux0.11內存管理   描述linux 0.11的內存管理主要內容。   1:內存初始化 linux 0.11最大支持16MB的物理內存。 main函數和mem_init函數對內存進行了初始化。 主要使用數組mem_map[]來標記相應的內存頁是否被占用。   memory_end是用BIOS中斷調用得到的實際內存大小。 if (memory_end > 16 * 1024 * 1024)     memory_end = 16 * 1024 * 1024;           # 因此最大只支持16MB內存 if (memory_end > 12*1024*1024)                 buffer_memory_end = 4 * 1024 * 1024;   # buffer_memory_end為高速緩存末端地址,其大小於機器總內存大小相關 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);    在mem_init中會對mem_map[]數組進行初始化。 在1MB~16MB之間,共有(15 * 1024 * 1024) >> 12 = 3840頁。 定義數組mem_map[3840]對應於這段內存的每一頁,在main_memory_start和memory_end之間的頁,相應的mem_map[i]的值 初始化為0,表示未使用,其余的項初始化為100,表示被占用。    2:基本頁面分配函數 有幾個基本的頁面分配和釋放的函數。 get_free_page():返回一個空閒頁面的物理地址, 該函數就是在mem_map數組中查找值為0的項,然後轉換成頁面物理地址返回。 free_page(phy_addr):釋放phy_addr指向的頁面, 釋放操作就是將phy_addr在mem_map中對應項的值進行減1。 get_empty_page(line_addr):該函數的參數指定的是線性地址,要求獲得一頁物理內存,並用line_addr指向這頁內存。   void get_empty_page(unsigned long address) {     unsigned long tmp;          if (!(tmp=get_free_page()) || !put_page(tmp, address)) {         free_page(tmp);         oom();        # 內存不夠     } } 明顯該函數先調用get_free_page獲得一頁物理內存, 然後用put_page對這頁物理內存的物理地址和線性地址之間建立映射。   建立映射的過程:   對於32位的線性地址, 高10位表示頁目錄索引, 中間10位為頁表索引, 低12位為頁內偏移。 因此給定一個線性地址,我們就能通過頁目錄基地址和線性地址高10位來確定它的頁目錄項。 在Linux 0.11中,頁目錄基地址就是0。   put_page:     page_table = (unsigned long *) ((line_addr >> 20) & 0xffc)      #  獲得頁目錄項的指針     如果該頁目錄項所指向的頁表是存在的, 則利用線性地址的中間10位,定位到頁表中的相應頁表項, 並將物理地址保存進去即可建立映射。  若頁表不存在,則用get_free_page首先分配一頁作為頁表,再去建立映射。   不管是建立映射還是進行頁表拷貝,都是先考慮頁目錄,再考慮頁表。   3:sys_fork與copy_page_tables函數 在sys_fork時會調用copy_process,copy_process中會調用copy_mem函數, 該函數會將父進程的頁表拷貝給子進程, 這是父進程和子進程會共享相應的代碼和數據段,只有當父進程或子進程對共享的內存進行寫操作時,才會為子進程分配內存,即為寫時復制。   copy_mem是調用copy_page_table進行頁表拷貝的。   copy_page_table(old_data_base, new_data_base, data_limit) 將父進程的線性地址old_data_base ~ old_data_base+data_limit對應的頁表,拷貝給子進程。 在拷貝過程中,將每個頁表項設定為只讀, 並且執行相應的mem_map[i]++(相當於添加引用計數)   4:頁出錯異常處理 有兩種不同的頁出錯: i)頁表項指向的頁不存在,即頁表項的存在位的值為0. ii)頁保護機制。 寫只讀頁面時出錯。   但出現頁錯誤時,會發生int 14中斷。系統會執行_page_fault:異常處理代碼。 該代碼會根據兩種不同的頁錯誤,分別執行do_no_page和do_wp_page   do_wp_page(error_code, address) 該函數主要是實現了寫時復制功能, 在copy_page_table時,將父進程和子進程的頁表都設定成了只讀,當訪問了其中一個頁面後, 會觸發中斷並執行do_wp_page函數。 此函數會分配一頁新的物理內存, 並將相應的頁表項設成可讀寫。   do_no_page(error_code, address) 該函數可處理兩種情況: i)在應用分配內存時,內核並不會實際分配物理內存, 只有在訪問相應內存時,才會分配。 ii)在執行exec系列函數時,同樣只有在訪問相應內存時,才會去讀文件, 對於第一種情況, do_no_page直接調用get_empty_page函數,獲取一頁內存。 對於第二種情況,有兩步過程。 i)調用share_page函數。 該函數的主要目的是共享代碼和數據段。 如果一個可執行文件,已經有一個進程實例在執行,那麼 新進程可以和其他進程共享該可執行文件的代碼和數據段。 ii)如果只執行過一次該文件, 那就先調用get_free_page函數,將文件內容讀入內存,然後用put_page函數建立映射。  
Copyright © Linux教程網 All Rights Reserved