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

Linux內存管理之伙伴系統(內存釋放)

Linux內核伙伴系統中頁面釋放,主函數為free_pages()

一、上層操作

  1. /*用虛擬地址進行釋放*/  
  2. void free_pages(unsigned long addr, unsigned int order)  
  3. {  
  4.     if (addr != 0) {  
  5.         VM_BUG_ON(!virt_addr_valid((void *)addr));  
  6.         __free_pages(virt_to_page((void *)addr), order);/*具體的釋放函數*/  
  7.     }  
  8. }  
 
  1. /*釋放頁面*/  
  2. void __free_pages(struct page *page, unsigned int order)  
  3. {  
  4.     if (put_page_testzero(page)) {/*count值減一為0時釋放*/  
  5.         /*調試*/  
  6.         trace_mm_page_free_direct(page, order);  
  7.         if (order == 0)  
  8.             free_hot_page(page);/*釋放單個頁面*/  
  9.         else  
  10.             __free_pages_ok(page, order);  
  11.     }  
  12. }  

二、釋放單個頁面

釋放單個頁面free_hot_page()調用free_hot_cold_page()函數

  1. static void free_hot_cold_page(struct page *page, int cold)  
  2. {  
  3.     struct zone *zone = page_zone(page);  
  4.     struct per_cpu_pages *pcp;  
  5.     unsigned long flags;  
  6.     int migratetype;  
  7.     int wasMlocked = __TestClearPageMlocked(page);  
  8.     /*調試代碼*/  
  9.     kmemcheck_free_shadow(page, 0);  
  10.   
  11.     if (PageAnon(page))  
  12.         page->mapping = NULL;  
  13.     if (free_pages_check(page))  
  14.         return;  
  15.   
  16.     if (!PageHighMem(page)) {  
  17.         debug_check_no_locks_freed(page_address(page), PAGE_SIZE);  
  18.         debug_check_no_obj_freed(page_address(page), PAGE_SIZE);  
  19.     }  
  20.     /*x86下為空*/  
  21.     arch_free_page(page, 0);  
  22.     /*調試用*/  
  23.     kernel_map_pages(page, 1, 0);  
  24.     /*獲得zone對應cpu的pcp*/  
  25.     pcp = &zone_pcp(zone, get_cpu())->pcp;  
  26.     /*獲得頁面的migratetype*/  
  27.     migratetype = get_pageblock_migratetype(page);  
  28.     set_page_private(page, migratetype);/*設置私有位為參數*/  
  29.     local_irq_save(flags);/*保存中斷*/  
  30.     if (unlikely(wasMlocked))  
  31.         free_page_mlock(page);  
  32.     __count_vm_event(PGFREE);  
  33.   
  34.     /* 
  35.      * We only track unmovable, reclaimable and movable on pcp lists. 
  36.      * Free ISOLATE pages back to the allocator because they are being 
  37.      * offlined but treat RESERVE as movable pages so we can get those 
  38.      * areas back if necessary. Otherwise, we may have to free 
  39.      * excessively into the page allocator 
  40.      */  
  41.     if (migratetype >= MIGRATE_PCPTYPES) {  
  42.         if (unlikely(migratetype == MIGRATE_ISOLATE)) {  
  43.             /*釋放到伙伴系統 */  
  44.             free_one_page(zone, page, 0, migratetype);  
  45.             goto out;  
  46.         }  
  47.         migratetype = MIGRATE_MOVABLE;  
  48.     }  
  49.   
  50.     if (cold)/*加入到pcp鏈表尾部*/  
  51.         list_add_tail(&page->lru, &pcp->lists[migratetype]);  
  52.     else/*加入到pcp鏈表頭部*/  
  53.         list_add(&page->lru, &pcp->lists[migratetype]);  
  54.     pcp->count++;/*pcp計數加一*/  
  55.     if (pcp->count >= pcp->high) {/*當pcp中頁面數量超過他的最高值時, 
  56.         釋放pcp->batch個頁面到伙伴系統中*/  
  57.         free_pcppages_bulk(zone, pcp->batch, pcp);  
  58.         pcp->count -= pcp->batch;/*頁面數減去釋放的頁面數量*/  
  59.     }  
  60.   
  61. out:  
  62.     local_irq_restore(flags);/*回復中斷*/  
  63.     put_cpu();  
  64. }  

從pcp中釋放頁面到伙伴系統中

free_pcppages_bulk()

  1. are in same zone, and of same order.  
  2.  * count is the number of pages to free.  
  3.  *  
  4.  * If the zone was previously in an "all pages pinned" state then look to  
  5.  * see if this freeing clears that state.  
  6.  *  
  7.  * And clear the zone's pages_scanned counter, to hold off the "all pages are  
  8.  * pinned" detection logic.  
  9.  */  
  10.  /*從PCP中釋放count個頁面到伙伴系統中*/  
  11. static void free_pcppages_bulk(struct zone *zone, int count,  
  12.                     struct per_cpu_pages *pcp)  
  13. {  
  14.     int migratetype = 0;  
  15.     int batch_free = 0;  
  16.     /* 
  17.      * 雖然管理區可以按照CPU節點分類,但是也可以跨CPU節點進行內存分配, 
  18.      * 因此這裡需要用自旋鎖保護管理區  
  19.      * 使用每CPU緩存的目的,也是為了減少使用這把鎖。 
  20.      */  
  21.     spin_lock(&zone->lock);  
  22.     /* all_unreclaimable代表了內存緊張程度,釋放內存後,將此標志清除 */  
  23.     zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE);  
  24.     zone->pages_scanned = 0;/* pages_scanned代表最後一次內存緊張以來,頁面回收過程已經掃描的頁數。 
  25.     目前正在釋放內存,將此清0,待回收過程隨後回收時重新計數 */  
  26.   
  27.     /*增加管理區空閒頁數*/  
  28.     __mod_zone_page_state(zone, NR_FREE_PAGES, count);  
  29.     while (count) {  
  30.         struct page *page;  
  31.         struct list_head *list;  
  32.   
  33.         /* 
  34.          * Remove pages from lists in a round-robin fashion. A 
  35.          * batch_free count is maintained that is incremented when an 
  36.          * empty list is encountered.  This is so more pages are freed 
  37.          * off fuller lists instead of spinning excessively around empty 
  38.          * lists 
  39.          */  
  40.         do {/*從pcp的三類鏈表中找出不空的一個,釋放*/  
  41.             batch_free++;/*參看英文注釋*/  
  42.             if (++migratetype == MIGRATE_PCPTYPES)  
  43.                 migratetype = 0;  
  44.             list = &pcp->lists[migratetype];  
  45.         } while (list_empty(list));  
  46.   
  47.         do {  
  48.             page = list_entry(list->prev, struct page, lru);  
  49.             /* must delete as __free_one_page list manipulates */  
  50.             list_del(&page->lru);  
  51.             /*釋放單個頁面到伙伴系統,注意這裡的分類回收*/  
  52.             __free_one_page(page, zone, 0, migratetype);  
  53.             trace_mm_page_pcpu_drain(page, 0, migratetype);  
  54.         } while (--count && --batch_free && !list_empty(list));  
  55.     }  
  56.     spin_unlock(&zone->lock);  
  57. }  
Copyright © Linux教程網 All Rights Reserved