The call relationship between the Linux memory deallocation functions is as shown in
Hi
/* Release with virtual address */void free_pages (unsigned long addr, unsigned int order) {if (addr! = 0) {vm_bug_on (!virt_addr_valid (void *) a DDR); __free_pages (Virt_to_page ((void *) addr), order);/* Specific release function */}}
void __free_pages (struct page *page, unsigned int order) {if (Put_page_testzero (page)) {/* * Judgment page not used */trace_mm_page_free_ Direct (page, order), if (order = = 0)/* page is released to the Per CPU page box Cache */free_hot_page (page), else/ * Multiple pages are released to the partner system */__FREE_PAGES_OK (page, order);}}
release a single page free_hot_page () called free_hot_cold_page () function
/* * Free a 0-order page * cold = 1? Free a cold page:free a hot page */void free_hot_cold_page (struct page *page, int cold) {struct Zone *zone = Page_zone (PA GE); struct per_cpu_pages *pcp;unsigned long flags;int migratetype;int wasmlocked = __testclearpagemlocked (page); Free_pages_prepare (page, 0)) Return;migratetype = Get_pageblock_migratetype (page); set_page_private (page, Migratetype); Local_irq_save (Flags), if (Unlikely (wasmlocked)) Free_page_mlock (page); __count_vm_event (pgfree);/* * We have track unmovable, reclaimable and movable on the PCP lists. * Free ISOLATE pages back to the allocator because they is being * offlined but treat reserve as movable pages so we can Get those * areas back if necessary. Otherwise, we may have to free * excessively into the page allocator */if (migratetype >= migrate_pcptypes) {if (unlike Ly (Migratetype = = migrate_isolate)) {Free_one_page (zone, page, 0, Migratetype); /* Release to partner system */ goto out;} Migratetype = migrate_movable;} PCP = &this_cPu_ptr (zone->pageset)->pcp; /* get zone corresponding CPU pcp*/ if (Cold) List_add_tail (&PAGE->LRU, & Pcp->lists[migratetype]); Elselist_add (&PAGE->LRU, &pcp->lists[migratetype]);p cp->count++;if (Pcp->count >= Pcp->high) {/* When the number of pages in the PCP exceeds his maximum value, free_pcppages_bulk (Zone, Pcp->batch, PCP); release Pcp->batch pages into the partner system */ Pcp->count-= Pcp->batch;} Out:local_irq_restore (flags); * reply Interrupt */ }to complete the release by calling Free_one_page ()-->__free_one_page ( )
static inline void __free_one_page (struct page *page,struct zone *zone, unsigned int order,int migratetype) {unsigned long Page_idx;if (Unlikely (Pagecompound (page))) if (unlikely (page, order)) return; vm_bug_on (Migratetype = =-1);/* Gets the offset of the page box in the largest block */page_idx = PAGE_TO_PFN (page) & ((1 << max_order)-1); Vm_bug_on (Page_idx & ((1 << Order)-1)); vm_bug_on (Bad_range (Zone, page));/* If the order is less than max_order-1 there is a chance of merging */while (Order < max_order-1) {unsigned long combined_ Idx;struct Page *buddy;/* finds the partner block corresponding to the block of page */buddy = __page_find_buddy (page, page_idx, order);/* Do not perform the following merge operation if the partner block is not idle */ if (!page_is_buddy (page, buddy, order)) break;/* Our buddy are free, the merge with it and move up one order. */list_del (&BUDDY->LRU);/* Remove the partner block from the Block list */zone->free_area[order].nr_free--;rmv_page_order (buddy);/* Calculates the offset of the start Page box for the merged block */COMBINED_IDX = __find_combined_index (page_idx, order);/* Gets the start Page descriptor of the merged block */page = page + (COMBINED_IDX- PAGE_IDX);p Age_idx = combined_idx;/* Modify the start Page offset */order++;/* Order of the Block plus1 indicates that the merge completes */}/* the order of the Block */set_page_order (page, order);/* Adds a new block to the corresponding linked list */list_add (&page->lru,&zone->free _area[order].free_list[migratetype]); zone->free_area[order].nr_free++;}_page_find_buddy () is used to find the partner that is releasing the block, if an idle partner block is found to be used by _find_combined_index () to locate the merge block's start Page box, because a block's partner block may be in front of the block, It is also possible that the implementations of the two functions are very concise and ingenious, and are all implemented by bit manipulation .
Static inline struct page *__page_find_buddy (struct page *page, unsigned long page_idx, unsigned int order) {unsigned long Buddy_idx = page_idx ^ (1 << order); return page + (BUDDY_IDX-PAGE_IDX);}
Static inline unsigned long__find_combined_index (unsigned long page_idx, unsigned int order) {return (Page_idx & ~ (1 &L t;< order));}
Can be an example of practical proof ... This algorithm is relatively fast.
from PCP release the page into the partner system;Free_pcppages_bulk ()
/* * Frees a number of pages from the PCP lists * assumes all pages on list is in same zone, and of same order. * Count is the number of pages and free. * If the zone is previously in an ' all pages pinned ' state and look to * see If this freeing clears. * * and clear the zone ' s pages_scanned counter, to hold off the "all pages is * pinned" detection logic. */static void Free_pcppages_bulk (struct zone *zone, int count,struct per_cpu_pages *PCP) {int migratetype = 0;int Batch_fre E = 0;int To_free = count; /* * Although the admin area can be categorized by CPU nodes, memory allocations can also be made across CPU nodes, & Nbsp;* therefore need to use the spin lock protection management Area * for the purpose of using per CPU cache, also in order to reduce the use of this lock. */ spin_lock (&zone->lock); zone->all_unreclaimable = 0; /* All_ Unreclaimable represents the amount of memory tension, after releasing memory, this flag clears */ zone->pages_scanned = 0;/* pages_scanned represents the number of pages that the page recycling process has scanned since the last memory tension. is currently releasing memory, clearing this 0, to be re-counted when the recycle process is subsequently recycled */ while (to_free) {struct page*page;struct list_head *list;/* * Remove pages from lists in a round-robin fashion. A * Batch_free Count is maintained, that's incremented when an * empty list is encountered. This was so more pages was freed * off Fuller lists instead of spinning excessively around empty * lists */do {batch_free++ if (++migratetype = = migrate_pcptypes) Migratetype = 0;list = &pcp->lists[migratetype];} while (list_empty);/* Find the one that is not empty from the list of three types of PCP, release *//* the only Non-empty list. Free them all. */if (Batch_free = = migrate_pcptypes) Batch_free = to_free;do {page = list_entry (list->prev, struct page, LRU);/* Must D Elete as __free_one_page list manipulates */list_del (&PAGE->LRU);/* migrate_movable list may include Migrate_ Reserves */__free_one_page (page, zone, 0, page_private (page)); /* release a single page to the partner system, pay attention to the classification of the recycling */ trace_mm_page_ Pcpu_drain (page, 0, Page_private (page));} while (--to_free &&--batch_free &&!list_empty (list));} __mod_zone_page_state (Zone, Nr_free_pagES, count); Spin_unlock (&zone->lock);}
static void __free_pages_ok (struct page *page, unsigned int order) {unsigned long flags;int wasmlocked = __testclearpagemlo cked (page), if (!free_pages_prepare (page, order)) Return;local_irq_save (Flags), if (Unlikely (wasmlocked)) Free_page_ Mlock (page); __count_vm_events (Pgfree, 1 << order) free_one_page (Page_zone (page), page, Order,get_pageblock_ Migratetype (page)); Local_irq_restore (flags);}
static bool Free_pages_prepare (struct page *page, unsigned int order) {int I;int bad = 0;trac E_mm_page_free (page, order); Kmemcheck_free_shadow (page, order), if (Pageanon (page)) page->mapping = null;for (i = 0; i < (1 << order); i++) Bad + = Free_pages_check (page + i);/* pages related check */if (bad) return false;if (! Pagehighmem (page)) {Debug_check_no_locks_freed (page_address (page), Page_size<<order);d ebug_check_no_obj_ Freed (page_address (page), page_size << order);} Arch_free_page (page, order); kernel_map_pages (page, 1 << order, 0);/* Debug, related macro definition */ return true;}
static void Free_one_page (struct zone *zone, struct page *page, int order,int migratetype) {spin_lock (&zone->lock) */* Get the Management Area spin lock */zone->all_unreclaimable = 0;/* as long as the page is released, you need to clear the two flags 0, indicating the fact that memory is no longer tense */zone->pages_scanned = 0;__free _one_page (page, zone, order, migratetype);/* Release to the specified partner system Type list */__mod_zone_page_state (zone, nr_free_pages, 1 << order); * Admin Area Idle page count */Spin_unlock (&zone->lock);}
Partner system memory release or call main process
1, if you are releasing a single page, you need to consider whether to release it to the partner system based on the page type, and add it to the PCP list. If there is too much memory in the PCP list, call the Free_pcppages_bulk () function to put large chunks of memory back into the partner system;
2, if you are releasing more than one page, call __free_one_page () directly to release to the partner system.
3, the consolidation of partners needs to be considered when releasing into a partner system.
Memory Management---memory release