歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux內存管理之伙伴系統(內存釋放)

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

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

從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. __mod_zone_page_state(zone, NR_FREE_PAGES, count);
  28. while (count) {
  29. struct page *page;
  30. struct list_head *list;
  31. /*
  32. * Remove pages from lists in a round-robin fashion. A
  33. * batch_free count is maintained that is incremented when an
  34. * empty list is encountered. This is so more pages are freed
  35. * off fuller lists instead of spinning excessively around empty
  36. * lists
  37. */
  38. do {/*從pcp的三類鏈表中找出不空的一個,釋放*/
  39. batch_free++;/*參看英文注釋*/
  40. if (++migratetype == MIGRATE_PCPTYPES)
  41. migratetype = 0;
  42. list = &pcp->lists[migratetype];
  43. } while (list_empty(list));
  44. do {
  45. page = list_entry(list->prev, struct page, lru);
  46. /* must delete as __free_one_page list manipulates */
  47. list_del(&page->lru);
  48. /*釋放單個頁面到伙伴系統,注意這裡的分類回收*/
  49. __free_one_page(page, zone, 0, migratetype);
  50. trace_mm_page_pcpu_drain(page, 0, migratetype);
  51. } while (--count && --batch_free && !list_empty(list));
  52. }
  53. spin_unlock(&zone->lock);
  54. }
Copyright © Linux教程網 All Rights Reserved