国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Home Web Front-end HTML Tutorial Scenario Analysis of Linux Kernel Source Code - Regular Swapping Out of User Pages of Memory Management_html/css_WEB-ITnose

Scenario Analysis of Linux Kernel Source Code - Regular Swapping Out of User Pages of Memory Management_html/css_WEB-ITnose

Jun 24, 2016 am 11:48 AM

We have seen that when allocating pages, if the number of pages is not enough, page_launder, reclaim_page, __free_page will be called to swap out the page and put it back into allocation.

In order to avoid temporarily searching for memory pages that can be swapped out and swapping them out when the CPU is busy, that is, when a page fault exception occurs, the Linux kernel regularly checks and pre-registers a number of pages. Pages are swapped out to free up space to reduce the burden on the system when page fault exceptions occur.

To this end, a "patron saint" kswapd and kreclaimd are set up in the Linux kernel to regularly swap out pages.

static int __init kswapd_init(void){	printk("Starting kswapd v1.8\n");	swap_setup();	kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);	kernel_thread(kreclaimd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);	return 0;}
Started two kernel threads, kswapd and kreclaimd.


First analyze kswapd, the code is as follows:

int kswapd(void *unused){	struct task_struct *tsk = current;	tsk->session =1;	tsk->pgrp = 1;	strcpy(tsk->comm, "kswapd");	sigfillset(&tsk->blocked);	kswapd_task = tsk;		.....	tsk->flags |= PF_MEMALLOC;//執(zhí)行公務(wù),標(biāo)志位置1	/*	 * Kswapd main loop.	 */	for (;;) {		static int recalc = 0;		/* If needed, try to free some memory. */		if (inactive_shortage() || free_shortage()) {			int wait = 0;			/* Do we need to do some synchronous flushing? */			if (waitqueue_active(&kswapd_done))				wait = 1;			do_try_to_free_pages(GFP_KSWAPD, wait);//主體函數(shù)		}		......		refill_inactive_scan(6, 0);		......		......		if (!free_shortage() || !inactive_shortage()) {			interruptible_sleep_on_timeout(&kswapd_wait, HZ);//每隔1秒鐘喚醒一次,繼續(xù)執(zhí)行循環(huán)		......		} else if (out_of_memory()) {			oom_kill();		}	}}

In some simple After the initialization operation, the program enters an infinite loop. At the end of each loop, interruptible_sleep_on_timeout() is generally called to enter sleep, allowing the kernel to freely schedule other processes to run. However, the kernel will wake up after 1 second and schedule kswapd to continue running. At this time, kswapd will return to the place where the infinite loop began.


The main function executed by this function is do_try_to_free_pages, the code is as follows:

static int do_try_to_free_pages(unsigned int gfp_mask, int user){	int ret = 0;	......	if (free_shortage() || nr_inactive_dirty_pages > nr_free_pages() +			nr_inactive_clean_pages())		ret += page_launder(gfp_mask, user);	......	if (free_shortage() || inactive_shortage()) {		shrink_dcache_memory(6, gfp_mask);		shrink_icache_memory(6, gfp_mask);		ret += refill_inactive(gfp_mask, user);	} else {		......		kmem_cache_reap(gfp_mask);		ret = 1;	}	return ret;}
shrink_dcache_memory and shrink_icache_memory are used to recycle a large amount of accumulated memory. dentry data structure and inode data structure. These data structures are not released immediately after the file is closed, but are placed in the LRU queue as a backup in case they are needed for file operations in the near future.

kmem_cache_reap is used to harvest slab blocks. The slab management mechanism also tends to allocate and maintain more free physical pages and is not keen on returning these pages, so it will be harvested through kmem_cache_reap after a while.

1. The first thing we analyze is refill_inactive, the code is as follows:

static int refill_inactive(unsigned int gfp_mask, int user){	int priority, count, start_count, made_progress;	count = inactive_shortage() + free_shortage();	if (user)		count = (1 << page_cluster);	start_count = count;	/* Always trim SLAB caches when memory gets low. */	kmem_cache_reap(gfp_mask);//收割slab	priority = 6;//循環(huán)從優(yōu)先級(jí)最低的6級(jí)開(kāi)始,逐步加大"力度"直到0級(jí),	do {		made_progress = 0;		if (current->need_resched) {//內(nèi)核線程必須自律,因?yàn)橛肋h(yuǎn)不會(huì)返回用戶空間,就永遠(yuǎn)不會(huì)檢查這個(gè)標(biāo)志位			__set_current_state(TASK_RUNNING);//表示希望繼續(xù)執(zhí)行的愿望			schedule();//調(diào)度		}		while (refill_inactive_scan(priority, 1)) {			made_progress = 1;			if (--count <= 0)//達(dá)到目標(biāo),就提前結(jié)束				goto done;		}		......		shrink_dcache_memory(priority, gfp_mask);//回收積累起來(lái)的大量的dentry數(shù)據(jù)結(jié)構(gòu)和inode數(shù)據(jù)結(jié)構(gòu)		shrink_icache_memory(priority, gfp_mask);		......		while (swap_out(priority, gfp_mask)) {			made_progress = 1;			if (--count <= 0)//達(dá)到目標(biāo),就提前結(jié)束				goto done;		}		......		if (!inactive_shortage() || !free_shortage())			goto done;//不缺少頁(yè)面了,也提前結(jié)束		......		if (!made_progress)			priority--;	} while (priority >= 0);	/* Always end on a refill_inactive.., may sleep... */	while (refill_inactive_scan(0, 1)) {		if (--count <= 0)			goto done;	}done:	return (count < start_count);}

1. The refill_inactive_scan function, as follows:

int refill_inactive_scan(unsigned int priority, int oneshot){	struct list_head * page_lru;	struct page * page;	int maxscan, page_active = 0;	int ret = 0;	/* Take the lock while messing with the list... */	spin_lock(&pagemap_lru_lock);	maxscan = nr_active_pages >> priority;//當(dāng)priority為0時(shí),才掃描整個(gè)隊(duì)列	while (maxscan-- > 0 && (page_lru = active_list.prev) != &active_list) {		page = list_entry(page_lru, struct page, lru);		/* Wrong page on list?! (list corruption, should not happen) */		if (!PageActive(page)) {//是否是活躍的頁(yè)面			printk("VM: refill_inactive, wrong page on list.\n");			list_del(page_lru);			nr_active_pages--;			continue;		}		/* Do aging on the pages. */		if (PageTestandClearReferenced(page)) {//是否受到過(guò)訪問(wèn)			age_page_up_nolock(page);			page_active = 1;		} else {			age_page_down_ageonly(page);//沒(méi)有受到過(guò)訪問(wèn),減少頁(yè)面壽命			......			if (page->age == 0 && page_count(page) <=						(page->buffers ? 2 : 1)) {//如果頁(yè)面壽命為0,且使用計(jì)數(shù)為1(預(yù)讀后,未被進(jìn)程認(rèn)領(lǐng)的頁(yè)面)				deactivate_page_nolock(page);				page_active = 0;			} else {				page_active = 1;			}		}		......		if (page_active || PageActive(page)) {			list_del(page_lru);			list_add(page_lru, &active_list);		} else {			ret = 1;			if (oneshot)				break;		}	}	spin_unlock(&pagemap_lru_lock);	return ret;}
In this article Linux Kernel Source Code Scenario Analysis-Memory Management User Page Swapping,

After pre-reading, it was not The last usage count of the page claimed by the process is 1;

page->list is linked to mapping->clean_pages;

page->next_hash and page->pprev_hash are linked to global Hash table;

page->lru is linked to the global active_list;

After pre-reading, pages that are not claimed by the process will execute deactivate_page_nolock, the code is as follows:

void deactivate_page_nolock(struct page * page){	/*	 * One for the cache, one for the extra reference the	 * caller has and (maybe) one for the buffers.	 *	 * This isn't perfect, but works for just about everything.	 * Besides, as long as we don't move unfreeable pages to the	 * inactive_clean list it doesn't need to be perfect...	 */	int maxcount = (page->buffers ? 3 : 2);	page->age = 0;	ClearPageReferenced(page);	/*	 * Don't touch it if it's not on the active list.	 * (some pages aren't on any list at all)	 */	if (PageActive(page) && page_count(page) <= maxcount && !page_ramdisk(page)) {		del_page_from_active_list(page);		add_page_to_inactive_dirty_list(page);	}}

del_page_from_active_list function, as follows:

#define del_page_from_active_list(page) { \	list_del(&(page)->lru); \ 	ClearPageActive(page); \	nr_active_pages--; \	DEBUG_ADD_PAGE \	ZERO_PAGE_BUG \}


add_page_to_inactive_dirty_list function, as follows:

#define add_page_to_inactive_dirty_list(page) { \	DEBUG_ADD_PAGE \	ZERO_PAGE_BUG \	SetPageInactiveDirty(page); \	list_add(&(page)->lru, &inactive_dirty_list); \	nr_inactive_dirty_pages++; \	page->zone->inactive_dirty_pages++; \}
After pre-reading, the result of execution of pages that are not claimed by the process is:

The final usage count is 1;

page->list is linked to mapping->clean_pages; // Since it has not been visited

page->next_hash and page->pprev_hash are linked to the global Hash table;

page->lru is linked to the global inactive_dirty_list;

There is no need to disconnect the mapping, because there is no mapping in the first place.


2. The swap_out function is as follows:

static int swap_out(unsigned int priority, int gfp_mask){	int counter;	int __ret = 0;	......	counter = (nr_threads << SWAP_SHIFT) >> priority;//優(yōu)先級(jí)越大,counter越大	if (counter < 1)		counter = 1;	for (; counter >= 0; counter--) {		struct list_head *p;		unsigned long max_cnt = 0;		struct mm_struct *best = NULL;		int assign = 0;		int found_task = 0;	select:		spin_lock(&mmlist_lock);		p = init_mm.mmlist.next;		for (; p != &init_mm.mmlist; p = p->next) {			struct mm_struct *mm = list_entry(p, struct mm_struct, mmlist);	 		if (mm->rss <= 0)				continue;			found_task++;			/* Refresh swap_cnt? */			if (assign == 1) {				mm->swap_cnt = (mm->rss >> SWAP_SHIFT);				if (mm->swap_cnt < SWAP_MIN)					mm->swap_cnt = SWAP_MIN;			}			if (mm->swap_cnt > max_cnt) {//swap_cnt表示該進(jìn)程尚未被考察的頁(yè)面,找出swap_cnt最大的進(jìn)程				max_cnt = mm->swap_cnt;				best = mm;			}		}		/* Make sure it doesn't disappear */		if (best)			atomic_inc(&best->mm_users);//增加mm_users		spin_unlock(&mmlist_lock);		......		if (!best) {			if (!assign && found_task > 0) {				assign = 1;				goto select;			}			break;		} else {			__ret = swap_out_mm(best, gfp_mask);//執(zhí)行主體			mmput(best);//減少mm_users			break;		}	}	return __ret;}
swap_out_mm is called layer by layer, through swap_out_vma(), swap_out_pgd (), swap_out_pmd(), until try_to_swap_out, trying to swap out the memory page pointed to by a page table entry pte.

The try_to_swap_out function is as follows:

static int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, int gfp_mask){	pte_t pte;	swp_entry_t entry;	struct page * page;	int onlist;	pte = *page_table;	if (!pte_present(pte))//物理頁(yè)面是否在內(nèi)存中		goto out_failed;	page = pte_page(pte);	if ((!VALID_PAGE(page)) || PageReserved(page))		goto out_failed;	if (!mm->swap_cnt)		return 1;	mm->swap_cnt--;//被考察的頁(yè)面數(shù)減1	onlist = PageActive(page);	/* Don't look at this pte if it's been accessed recently. */	if (ptep_test_and_clear_young(page_table)) {//如果頁(yè)面被訪問(wèn)過(guò),那么直接out_failed		age_page_up(page);		goto out_failed;	}	if (!onlist)		/* The page is still mapped, so it can't be freeable... */		age_page_down_ageonly(page);	......	if (page->age > 0)//如果頁(yè)面的age不小于0,頁(yè)out_failed		goto out_failed;	if (TryLockPage(page))		goto out_failed;	......	pte = ptep_get_and_clear(page_table);//走到這里,說(shuō)明頁(yè)面最近沒(méi)有訪問(wèn)過(guò),且age小于0,清空頁(yè)目錄項(xiàng)	flush_tlb_page(vma, address);	......	if (PageSwapCache(page)) {//page結(jié)構(gòu)在swapper_space隊(duì)列中		entry.val = page->index;//盤上數(shù)據(jù)塊的位置		if (pte_dirty(pte))//回憶頁(yè)面換入時(shí),頁(yè)目錄項(xiàng)的屬性被設(shè)置為可寫,臟			set_page_dirty(page);//會(huì)執(zhí)行set_swap_pte:		swap_duplicate(entry);		set_pte(page_table, swp_entry_to_pte(entry));//頁(yè)目錄項(xiàng)指向盤上數(shù)據(jù)塊的地址drop_pte:		UnlockPage(page);		mm->rss--;		deactivate_page(page);//見(jiàn)上面的函數(shù)		page_cache_release(page);//使用計(jì)數(shù)減1out_failed:		return 0;	}        ......}
To turn an active page into an inactive and dirty page, two points must be met.

The first point is that it has not been accessed recently. The judgment standard is:

static inline  int ptep_test_and_clear_young(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep); }
That is, the accessed flag of the page directory entry, recall When the page is swapped in, the properties of the page directory entry are set to writable and dirty. When the memory mapping mechanism of the i386CPU maps a linear address to a physical address through a page table entry and a page table entry, and then accesses the physical address, it will automatically set the _PAGE_ACCESSED flag of the entry to 1.

Second point, page->age is less than 0.


set_page_dirty function, as follows:

static inline void set_page_dirty(struct page * page){	if (!test_and_set_bit(PG_dirty, &page->flags))		__set_page_dirty(page);}
void __set_page_dirty(struct page *page){	struct address_space *mapping = page->mapping;	spin_lock(&pagecache_lock);	list_del(&page->list);	list_add(&page->list, &mapping->dirty_pages);	spin_unlock(&pagecache_lock);	mark_inode_dirty_pages(mapping->host);}
page->flags corresponds to PG_dirty. And page->list is linked to mapping->dirty_pages.


Finally, try_to_swap_out is executed, and the result is:

The usage count is 1;

page ->list is linked to mapping->dirty_pages;

page->next_hash and page->pprev_hash are linked to the global Hash table;

page->lru is linked Global inactive_dirty_list;

? ? page->flags對(duì)應(yīng)為設(shè)置為PG_dirty。

? ? 由于out_failed返回0,使swap_out_mm能夠依次考察和處理一個(gè)進(jìn)程的所有頁(yè)面。


? ? 二、看完了refill_inactive,返回函數(shù)do_try_to_free_pages,來(lái)看一下page_launder,代碼如下:

int page_launder(int gfp_mask, int sync){	int launder_loop, maxscan, cleaned_pages, maxlaunder;	int can_get_io_locks;	struct list_head * page_lru;	struct page * page;	/*	 * We can only grab the IO locks (eg. for flushing dirty	 * buffers to disk) if __GFP_IO is set.	 */	can_get_io_locks = gfp_mask & __GFP_IO;	launder_loop = 0;	maxlaunder = 0;	cleaned_pages = 0;dirty_page_rescan:	spin_lock(&pagemap_lru_lock);	maxscan = nr_inactive_dirty_pages;	while ((page_lru = inactive_dirty_list.prev) != &inactive_dirty_list &&				maxscan-- > 0) {		page = list_entry(page_lru, struct page, lru);		/* Wrong page on list?! (list corruption, should not happen) */		if (!PageInactiveDirty(page)) {//如果不是不活躍臟的頁(yè)面,冤假錯(cuò)案			printk("VM: page_launder, wrong page on list.\n");			list_del(page_lru);			nr_inactive_dirty_pages--;			page->zone->inactive_dirty_pages--;			continue;		}		/* Page is or was in use?  Move it to the active list. */		if (PageTestandClearReferenced(page) || page->age > 0 ||   //這個(gè)以后會(huì)在單獨(dú)的博客中解釋				(!page->buffers && page_count(page) > 1) ||				page_ramdisk(page)) {			del_page_from_inactive_dirty_list(page);			add_page_to_active_list(page);			continue;		}		/*		 * The page is locked. IO in progress?		 * Move it to the back of the list.		 */		if (TryLockPage(page)) {//如果已經(jīng)上鎖			list_del(page_lru);			list_add(page_lru, &inactive_dirty_list);//掛在inactive_dirty_list的最后			continue;		}		/*		 * Dirty swap-cache page? Write it out if		 * last copy..		 */		if (PageDirty(page)) {//如果頁(yè)面是臟的			int (*writepage)(struct page *) = page->mapping->a_ops->writepage;			int result;			if (!writepage)				goto page_active;			/* First time through? Move it to the back of the list */			if (!launder_loop) {//循環(huán)第一遍launder_loop為0				list_del(page_lru);				list_add(page_lru, &inactive_dirty_list);//掛到inactive_dirty_list的最后				UnlockPage(page);				continue;			}			//第二次循環(huán),執(zhí)行到這里			ClearPageDirty(page);//清空臟標(biāo)志位			page_cache_get(page);//使用計(jì)數(shù)加1			spin_unlock(&pagemap_lru_lock);			result = writepage(page);//同步到磁盤,頁(yè)面就變干凈了			page_cache_release(page);//使用計(jì)數(shù)減1			/* And re-start the thing.. */			spin_lock(&pagemap_lru_lock);			if (result != 1)				continue;			/* writepage refused to do anything */			set_page_dirty(page);//不會(huì)執(zhí)行到這里			goto page_active;		}                //執(zhí)行到這里時(shí),一定是干凈的頁(yè)面		......		if (page->buffers) {			......		} else if (page->mapping && !PageDirty(page)) {//如果頁(yè)面是干凈的,包括剛才是臟的,現(xiàn)在變成干凈的			.......			del_page_from_inactive_dirty_list(page);			add_page_to_inactive_clean_list(page);			UnlockPage(page);			cleaned_pages++;		} else {page_active:			......			del_page_from_inactive_dirty_list(page);			add_page_to_active_list(page);			UnlockPage(page);		}	}	spin_unlock(&pagemap_lru_lock);	......	if (can_get_io_locks && !launder_loop && free_shortage()) {//缺少可供分配的頁(yè)面		launder_loop = 1;//一共最多進(jìn)行兩次循環(huán)		/* If we cleaned pages, never do synchronous IO. */		if (cleaned_pages)			sync = 0;		/* We only do a few "out of order" flushes. */		maxlaunder = MAX_LAUNDER;		/* Kflushd takes care of the rest. */		wakeup_bdflush(0);		goto dirty_page_rescan;//返回到dirty_page_rescan	}	/* Return the number of pages moved to the inactive_clean list. */	return cleaned_pages;}
? ? 其中del_page_from_inactive_dirty_list函數(shù),如下:

#define del_page_from_inactive_dirty_list(page) { \	list_del(&(page)->lru); \	ClearPageInactiveDirty(page); \	nr_inactive_dirty_pages--; \	page->zone->inactive_dirty_pages--; \	DEBUG_ADD_PAGE \	ZERO_PAGE_BUG \}

? ? add_page_to_inactive_clean_list函數(shù)如下:

#define add_page_to_inactive_clean_list(page) { \	DEBUG_ADD_PAGE \	ZERO_PAGE_BUG \	SetPageInactiveClean(page); \	list_add(&(page)->lru, &page->zone->inactive_clean_list); \	page->zone->inactive_clean_pages++; \}
? ??

? ? 最后執(zhí)行完page_launder,結(jié)果是:

? ? 使用計(jì)數(shù)為1;

? ? page->list鏈入mapping->dirty_pages或者clean_pages(保持原樣);

? ? page->next_hash和page->pprev_hash鏈入全局的Hash表;

? ? page->lru鏈入了page->zone->inactive_clean_list;


? ? 然后,我們分析kreclaimd,代碼如下:

int kreclaimd(void *unused){	struct task_struct *tsk = current;	pg_data_t *pgdat;	tsk->session = 1;	tsk->pgrp = 1;	strcpy(tsk->comm, "kreclaimd");	sigfillset(&tsk->blocked);	current->flags |= PF_MEMALLOC;//執(zhí)行公務(wù)	while (1) {		/*		 * We sleep until someone wakes us up from		 * page_alloc.c::__alloc_pages().		 */		interruptible_sleep_on(&kreclaimd_wait);		/*		 * Move some pages from the inactive_clean lists to		 * the free lists, if it is needed.		 */		pgdat = pgdat_list;		do {			int i;			for(i = 0; i < MAX_NR_ZONES; i++) {				zone_t *zone = pgdat->node_zones + i;				if (!zone->size)					continue;				while (zone->free_pages < zone->pages_low) {					struct page * page;					page = reclaim_page(zone);//主體代碼					if (!page)						break;					__free_page(page);				}			}			pgdat = pgdat->node_next;		} while (pgdat);	}}


? ??reclaim_page代碼如下:

struct page * reclaim_page(zone_t * zone){	struct page * page = NULL;	struct list_head * page_lru;	int maxscan;	/*	 * We only need the pagemap_lru_lock if we don't reclaim the page,	 * but we have to grab the pagecache_lock before the pagemap_lru_lock	 * to avoid deadlocks and most of the time we'll succeed anyway.	 */	spin_lock(&pagecache_lock);	spin_lock(&pagemap_lru_lock);	maxscan = zone->inactive_clean_pages;	while ((page_lru = zone->inactive_clean_list.prev) !=			&zone->inactive_clean_list && maxscan--) {//掃描zone->inactive_clean_list		page = list_entry(page_lru, struct page, lru);		/* Wrong page on list?! (list corruption, should not happen) */		if (!PageInactiveClean(page)) {//冤假錯(cuò)案			printk("VM: reclaim_page, wrong page on list.\n");			list_del(page_lru);			page->zone->inactive_clean_pages--;			continue;		}		/* Page is or was in use?  Move it to the active list. */		if (PageTestandClearReferenced(page) || page->age > 0 ||				(!page->buffers && page_count(page) > 1)) {//這個(gè)會(huì)用單獨(dú)的博客介紹			del_page_from_inactive_clean_list(page);			add_page_to_active_list(page);			continue;		}		/* The page is dirty, or locked, move to inactive_dirty list. */		if (page->buffers || PageDirty(page) || TryLockPage(page)) {			del_page_from_inactive_clean_list(page);			add_page_to_inactive_dirty_list(page);			continue;		}		/* OK, remove the page from the caches. */                if (PageSwapCache(page)) {//page結(jié)構(gòu)在swapper_space隊(duì)列中			__delete_from_swap_cache(page);//執(zhí)行這里			goto found_page;		}		if (page->mapping) {			__remove_inode_page(page);			goto found_page;		}		/* We should never ever get here. */		printk(KERN_ERR "VM: reclaim_page, found unknown page\n");		list_del(page_lru);		zone->inactive_clean_pages--;		UnlockPage(page);	}	/* Reset page pointer, maybe we encountered an unfreeable page. */	page = NULL;	goto out;found_page:	del_page_from_inactive_clean_list(page);//執(zhí)行這里	UnlockPage(page);	page->age = PAGE_AGE_START;	if (page_count(page) != 1)		printk("VM: reclaim_page, found page with count %d!\n",				page_count(page));out:	spin_unlock(&pagemap_lru_lock);	spin_unlock(&pagecache_lock);	memory_pressure++;	return page;}


? ??__delete_from_swap_cache函數(shù),代碼如下:

void __delete_from_swap_cache(struct page *page){	swp_entry_t entry;	entry.val = page->index;#ifdef SWAP_CACHE_INFO	swap_cache_del_total++;#endif	remove_from_swap_cache(page);	swap_free(entry);}
? ??remove_from_swap_cache函數(shù),代碼如下:

static inline void remove_from_swap_cache(struct page *page){	struct address_space *mapping = page->mapping;	if (mapping != &swapper_space)		BUG();	if (!PageSwapCache(page) || !PageLocked(page))		PAGE_BUG(page);	PageClearSwapCache(page);	ClearPageDirty(page);	__remove_inode_page(page);}
? ??__remove_inode_page函數(shù),代碼如下:

void __remove_inode_page(struct page *page){	if (PageDirty(page)) BUG();	remove_page_from_inode_queue(page);	remove_page_from_hash_queue(page);	page->mapping = NULL;}
? ??remove_page_from_inode_queue函數(shù),代碼如下:

static inline void remove_page_from_inode_queue(struct page * page){	struct address_space * mapping = page->mapping;	mapping->nrpages--;	list_del(&page->list);	page->mapping = NULL;}
? ??remove_page_from_hash_queue函數(shù),代碼如下:

static inline void remove_page_from_hash_queue(struct page * page){	struct page *next = page->next_hash;	struct page **pprev = page->pprev_hash;	if (next)		next->pprev_hash = pprev;	*pprev = next;	page->pprev_hash = NULL;	atomic_dec(&page_cache_size);}

? ??del_page_from_inactive_clean_list函數(shù),代碼如下:

#define del_page_from_inactive_clean_list(page) { \	list_del(&(page)->lru); \	ClearPageInactiveClean(page); \	page->zone->inactive_clean_pages--; \	DEBUG_ADD_PAGE \	ZERO_PAGE_BUG \}


? ??

? ? 最后執(zhí)行完reclaim_page,結(jié)果是:

? ? 使用計(jì)數(shù)為1;

? ? page->list為空;

? ? page->next_hash和page->pprev_hash位空;

? ? page->lru為空;


? ? 回到kreclaimd,會(huì)執(zhí)行__free_page,此時(shí)使用計(jì)數(shù)減為0,回收這個(gè)頁(yè)面到free_area[MAX_ORDER],下次alloc_page就能分配到了。

void __free_pages(struct page *page, unsigned long order){	if (!PageReserved(page) && put_page_testzero(page))//使用計(jì)數(shù)為0		__free_pages_ok(page, order);}

? ? 總結(jié):

? ??kswapd內(nèi)核線程:

? ? 1、refill_inactive_scan和swap_out,把活躍的頁(yè)面變成不活躍臟的頁(yè)面。挑選的原則是最近沒(méi)有被訪問(wèn),且age小于0。

? ? 2、page_launder,把不活躍臟的頁(yè)面變成不活躍干凈的頁(yè)面。


? ??kreclaimd內(nèi)核線程:

? ? 3、把不活躍干凈的頁(yè)面,所有的鏈表關(guān)系都清除,但使用計(jì)數(shù)仍然為1。

? ? 4、__free_page,此時(shí)使用計(jì)數(shù)減為0,回收這個(gè)頁(yè)面到free_area[MAX_ORDER],下次alloc_page就能分配到了。

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

PHP Tutorial
1502
276
Implementing Clickable Buttons Using the HTML button Element Implementing Clickable Buttons Using the HTML button Element Jul 07, 2025 am 02:31 AM

To use HTML button elements to achieve clickable buttons, you must first master its basic usage and common precautions. 1. Create buttons with tags and define behaviors through type attributes (such as button, submit, reset), which is submitted by default; 2. Add interactive functions through JavaScript, which can be written inline or bind event listeners through ID to improve maintenance; 3. Use CSS to customize styles, including background color, border, rounded corners and hover/active status effects to enhance user experience; 4. Pay attention to common problems: make sure that the disabled attribute is not enabled, JS events are correctly bound, layout occlusion, and use the help of developer tools to troubleshoot exceptions. Master this

Configuring Document Metadata Within the HTML head Element Configuring Document Metadata Within the HTML head Element Jul 09, 2025 am 02:30 AM

Metadata in HTMLhead is crucial for SEO, social sharing, and browser behavior. 1. Set the page title and description, use and keep it concise and unique; 2. Add OpenGraph and Twitter card information to optimize social sharing effects, pay attention to the image size and use debugging tools to test; 3. Define the character set and viewport settings to ensure multi-language support is adapted to the mobile terminal; 4. Optional tags such as author copyright, robots control and canonical prevent duplicate content should also be configured reasonably.

Best HTML tutorial for beginners in 2025 Best HTML tutorial for beginners in 2025 Jul 08, 2025 am 12:25 AM

TolearnHTMLin2025,chooseatutorialthatbalanceshands-onpracticewithmodernstandardsandintegratesCSSandJavaScriptbasics.1.Prioritizehands-onlearningwithstep-by-stepprojectslikebuildingapersonalprofileorbloglayout.2.EnsureitcoversmodernHTMLelementssuchas,

HTML for email templates tutorial HTML for email templates tutorial Jul 10, 2025 pm 02:01 PM

How to make HTML mail templates with good compatibility? First, you need to build a structure with tables to avoid using div flex or grid layout; secondly, all styles must be inlined and cannot rely on external CSS; then the picture should be added with alt description and use a public URL, and the buttons should be simulated with a table or td with background color; finally, you must test and adjust the details on multiple clients.

How to associate captions with images or media using the html figure and figcaption elements? How to associate captions with images or media using the html figure and figcaption elements? Jul 07, 2025 am 02:30 AM

Using HTML sums allows for intuitive and semantic clarity to add caption text to images or media. 1. Used to wrap independent media content, such as pictures, videos or code blocks; 2. It is placed as its explanatory text, and can be located above or below the media; 3. They not only improve the clarity of the page structure, but also enhance accessibility and SEO effect; 4. When using it, you should pay attention to avoid abuse, and apply to content that needs to be emphasized and accompanied by description, rather than ordinary decorative pictures; 5. The alt attribute that cannot be ignored, which is different from figcaption; 6. The figcaption is flexible and can be placed at the top or bottom of the figure as needed. Using these two tags correctly helps to build semantic and easy to understand web content.

How to handle forms submission in HTML without a server? How to handle forms submission in HTML without a server? Jul 09, 2025 am 01:14 AM

When there is no backend server, HTML form submission can still be processed through front-end technology or third-party services. Specific methods include: 1. Use JavaScript to intercept form submissions to achieve input verification and user feedback, but the data will not be persisted; 2. Use third-party serverless form services such as Formspree to collect data and provide email notification and redirection functions; 3. Use localStorage to store temporary client data, which is suitable for saving user preferences or managing single-page application status, but is not suitable for long-term storage of sensitive information.

What are the most commonly used global attributes in html? What are the most commonly used global attributes in html? Jul 10, 2025 am 10:58 AM

class, id, style, data-, and title are the most commonly used global attributes in HTML. class is used to specify one or more class names to facilitate style setting and JavaScript operations; id provides unique identifiers for elements, suitable for anchor jumps and JavaScript control; style allows for inline styles to be added, suitable for temporary debugging but not recommended for large-scale use; data-properties are used to store custom data, which is convenient for front-end and back-end interaction; title is used to add mouseover prompts, but its style and behavior are limited by the browser. Reasonable selection of these attributes can improve development efficiency and user experience.

Implementing Native Lazy Loading for Images in HTML Implementing Native Lazy Loading for Images in HTML Jul 12, 2025 am 12:48 AM

Native lazy loading is a built-in browser function that enables lazy loading of pictures by adding loading="lazy" attribute to the tag. 1. It does not require JavaScript or third-party libraries, and is used directly in HTML; 2. It is suitable for pictures that are not displayed on the first screen below the page, picture gallery scrolling add-ons and large picture resources; 3. It is not suitable for pictures with first screen or display:none; 4. When using it, a suitable placeholder should be set to avoid layout jitter; 5. It should optimize responsive image loading in combination with srcset and sizes attributes; 6. Compatibility issues need to be considered. Some old browsers do not support it. They can be used through feature detection and combined with JavaScript solutions.

See all articles