日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

万字整理,图解Linux内存管理所有知识点

發布時間:2024/4/11 linux 83 豆豆
生活随笔 收集整理的這篇文章主要介紹了 万字整理,图解Linux内存管理所有知识点 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux的內存管理可謂是學好Linux的必經之路,也是Linux的關鍵知識點,有人說打通了內存管理的知識,也就打通了Linux的任督二脈,這一點不夸張。有人問網上有很多Linux內存管理的內容,為什么還要看你這一篇,這正是我寫此文的原因,網上碎片化的相關知識點大都是東拼西湊,先不說正確性與否,就連基本的邏輯都沒有搞清楚,我可以負責任的說Linux內存管理只需要看此文一篇就可以讓你入Linux內核的大門,省去你東找西找的時間,讓你形成內存管理知識的閉環。

文章比較長,做好準備,深呼吸,讓我們一起打開Linux內核的大門!

Linux內存管理之CPU訪問內存的過程

我喜歡用圖的方式來說明問題,簡單直接:

藍色部分是cpu,灰色部分是內存,白色部分就是cpu訪問內存的過程,也是地址轉換的過程。在解釋地址轉換的本質前我們先理解下幾個概念:

  • TLB:MMU工作的過程就是查詢頁表的過程。如果把頁表放在內存中查詢的時候開銷太大,因此為了提高查找效率,專門用一小片訪問更快的區域存放地址轉換條目。(當頁表內容有變化的時候,需要清除TLB,以防止地址映射出錯。)

  • Caches:cpu和內存之間的緩存機制,用于提高訪問速率,armv8架構的話上圖的caches其實是L2 Cache,這里就不做進一步解釋了。

  • 虛擬地址轉換為物理地址的本質

    我們知道內核中的尋址空間大小是由CONFIG_ARM64_VA_BITS控制的,這里以48位為例,ARMv8中,Kernel Space的頁表基地址存放在TTBR1_EL1寄存器中,User Space頁表基地址存放在TTBR0_EL0寄存器中,其中內核地址空間的高位為全1,(0xFFFF0000_00000000 ~ 0xFFFFFFFF_FFFFFFFF),用戶地址空間的高位為全0,(0x00000000_00000000 ~ 0x0000FFFF_FFFFFFFF)

    有了宏觀概念,下面我們以內核態尋址過程為例看下是如何把虛擬地址轉換為物理地址的。

    我們知道linux采用了分頁機制,通常采用四級頁表,頁全局目錄(PGD),頁上級目錄(PUD),頁中間目錄(PMD),頁表(PTE)。如下:

  • 從CR3寄存器中讀取頁目錄所在物理頁面的基址(即所謂的頁目錄基址),從線性地址的第一部分獲取頁目錄項的索引,兩者相加得到頁目錄項的物理地址。

  • 第一次讀取內存得到pgd_t結構的目錄項,從中取出物理頁基址取出,即頁上級頁目錄的物理基地址。

  • 從線性地址的第二部分中取出頁上級目錄項的索引,與頁上級目錄基地址相加得到頁上級目錄項的物理地址。

  • 第二次讀取內存得到pud_t結構的目錄項,從中取出頁中間目錄的物理基地址。

  • 從線性地址的第三部分中取出頁中間目錄項的索引,與頁中間目錄基址相加得到頁中間目錄項的物理地址。

  • 第三次讀取內存得到pmd_t結構的目錄項,從中取出頁表的物理基地址。

  • 從線性地址的第四部分中取出頁表項的索引,與頁表基址相加得到頁表項的物理地址。

  • 第四次讀取內存得到pte_t結構的目錄項,從中取出物理頁的基地址。

  • 從線性地址的第五部分中取出物理頁內偏移量,與物理頁基址相加得到最終的物理地址。

  • 第五次讀取內存得到最終要訪問的數據。

  • 整個過程是比較機械的,每次轉換先獲取物理頁基地址,再從線性地址中獲取索引,合成物理地址后再訪問內存。不管是頁表還是要訪問的數據都是以頁為單位存放在主存中的,因此每次訪問內存時都要先獲得基址,再通過索引(或偏移)在頁內訪問數據,因此可以將線性地址看作是若干個索引的集合。

    Linux內存初始化

    有了armv8架構訪問內存的理解,我們來看下linux在內存這塊的初始化就更容易理解了。

    創建啟動頁表:

    在匯編代碼階段的head.S文件中,負責創建映射關系的函數是create_page_tables。create_page_tables函數負責identity mapping和kernel image mapping。

    • identity map:是指把idmap_text區域的物理地址映射到相等的虛擬地址上,這種映射完成后,其虛擬地址等于物理地址。idmap_text區域都是一些打開MMU相關的代碼。

    • kernel image map:將kernel運行需要的地址(kernel txt、rodata、data、bss等等)進行映射。

    arch/arm64/kernel/head.S: ENTRY(stext)bl??????preserve_boot_argsbl??????el2_setup???????????????????????//?Drop?to?EL1,?w0=cpu_boot_modeadrp????x23,?__PHYS_OFFSETand?????x23,?x23,?MIN_KIMG_ALIGN?-?1????//?KASLR?offset,?defaults?to?0bl??????set_cpu_boot_mode_flagbl??????__create_page_tables/**?The?following?calls?CPU?setup?code,?see?arch/arm64/mm/proc.S?for*?details.*?On?return,?the?CPU?will?be?ready?for?the?MMU?to?be?turned?on?and*?the?TCR?will?have?been?set.*/bl??????__cpu_setup?????????????????????//?initialise?processorb???????__primary_switch ENDPROC(stext)

    __create_page_tables主要執行的就是identity map和kernel image map:

    ?__create_page_tables: ......create_pgd_entry?x0,?x3,?x5,?x6mov?????x5,?x3??????????????????????????//?__pa(__idmap_text_start)adr_l???x6,?__idmap_text_end????????????//?__pa(__idmap_text_end)create_block_map?x0,?x7,?x3,?x5,?x6/**?Map?the?kernel?image?(starting?with?PHYS_OFFSET).*/adrp????x0,?swapper_pg_dirmov_q???x5,?KIMAGE_VADDR?+?TEXT_OFFSET??//?compile?time?__va(_text)add?????x5,?x5,?x23?????????????????????//?add?KASLR?displacementcreate_pgd_entry?x0,?x5,?x3,?x6adrp????x6,?_end????????????????????????//?runtime?__pa(_end)adrp????x3,?_text???????????????????????//?runtime?__pa(_text)sub?????x6,?x6,?x3??????????????????????//?_end?-?_textadd?????x6,?x6,?x5??????????????????????//?runtime?__va(_end)create_block_map?x0,?x7,?x3,?x5,?x6......

    其中調用create_pgd_entry進行PGD及所有中間level(PUD, PMD)頁表的創建,調用create_block_map進行PTE頁表的映射。關于四級頁表的關系如下圖所示,這里就不進一步解釋了。

    匯編結束后的內存映射關系如下圖所示:

    等內存初始化后就可以進入真正的內存管理了,初始化我總結了一下,大體分為四步:

  • 物理內存進系統前

  • 用memblock模塊來對內存進行管理

  • 頁表映射

  • zone初始化

  • Linux是如何組織物理內存的?

    • node 目前計算機系統有兩種體系結構:

  • 非一致性內存訪問 NUMA(Non-Uniform Memory Access)意思是內存被劃分為各個node,訪問一個node花費的時間取決于CPU離這個node的距離。每一個cpu內部有一個本地的node,訪問本地node時間比訪問其他node的速度快

  • 一致性內存訪問 UMA(Uniform Memory Access)也可以稱為SMP(Symmetric Multi-Process)對稱多處理器。意思是所有的處理器訪問內存花費的時間是一樣的。也可以理解整個內存只有一個node。

    • zone

    ZONE的意思是把整個物理內存劃分為幾個區域,每個區域有特殊的含義

    • page

    代表一個物理頁,在內核中一個物理頁用一個struct page表示。

    • page frame

    為了描述一個物理page,內核使用struct page結構來表示一個物理頁。假設一個page的大小是4K的,內核會將整個物理內存分割成一個一個4K大小的物理頁,而4K大小物理頁的區域我們稱為page frame

    • page frame num(pfn)

    pfn是對每個page frame的編號。故物理地址和pfn的關系是:

    物理地址>>PAGE_SHIFT = pfn

    • pfn和page的關系

    內核中支持了好幾個內存模型:CONFIG_FLATMEM(平坦內存模型)CONFIG_DISCONTIGMEM(不連續內存模型)CONFIG_SPARSEMEM_VMEMMAP(稀疏的內存模型)目前ARM64使用的稀疏的類型模式。

    系統啟動的時候,內核會將整個struct page映射到內核虛擬地址空間vmemmap的區域,所以我們可以簡單的認為struct page的基地址是vmemmap,則:

    vmemmap+pfn的地址就是此struct page對應的地址。

    Linux分區頁框分配器

    頁框分配在內核里的機制我們叫做分區頁框分配器(zoned page frame allocator),在linux系統中,分區頁框分配器管理著所有物理內存,無論你是內核還是進程,都需要請求分區頁框分配器,這時才會分配給你應該獲得的物理內存頁框。當你所擁有的頁框不再使用時,你必須釋放這些頁框,讓這些頁框回到管理區頁框分配器當中。

    有時候目標管理區不一定有足夠的頁框去滿足分配,這時候系統會從另外兩個管理區中獲取要求的頁框,但這是按照一定規則去執行的,如下:

    • 如果要求從DMA區中獲取,就只能從ZONE_DMA區中獲取。

    • 如果沒有規定從哪個區獲取,就按照順序從 ZONE_NORMAL -> ZONE_DMA 獲取。

    • 如果規定從HIGHMEM區獲取,就按照順序從 ZONE_HIGHMEM -> ZONE_NORMAL -> ZONE_DMA 獲取。

    內核中根據不同的分配需求有6個函數接口來請求頁框,最終都會調用到__alloc_pages_nodemask。

    struct?page?* __alloc_pages_nodemask(gfp_t?gfp_mask,?unsigned?int?order,?int?preferred_nid,nodemask_t?*nodemask) {page?=?get_page_from_freelist(alloc_mask,?order,?alloc_flags,?&ac);//fastpath分配頁面:從pcp(per_cpu_pages)和伙伴系統中正常的分配內存空間......page?=?__alloc_pages_slowpath(alloc_mask,?order,?&ac);//slowpath分配頁面:如果上面沒有分配到空間,調用下面函數慢速分配,允許等待和回收...... }

    在頁面分配時,有兩種路徑可以選擇,如果在快速路徑中分配成功了,則直接返回分配的頁面;快速路徑分配失敗則選擇慢速路徑來進行分配。總結如下:

    • 正常分配(或叫快速分配):

  • 如果分配的是單個頁面,考慮從per CPU緩存中分配空間,如果緩存中沒有頁面,從伙伴系統中提取頁面做補充。

  • 分配多個頁面時,從指定類型中分配,如果指定類型中沒有足夠的頁面,從備用類型鏈表中分配。最后會試探保留類型鏈表。

    • 慢速(允許等待和頁面回收)分配:

  • 當上面兩種分配方案都不能滿足要求時,考慮頁面回收、殺死進程等操作后在試。

  • Linux頁框分配器之伙伴算法

    static?struct?page?* get_page_from_freelist(gfp_t?gfp_mask,?unsigned?int?order,?int?alloc_flags,const?struct?alloc_context?*ac) {for_next_zone_zonelist_nodemask(zone,?z,?ac->zonelist,?ac->high_zoneidx,?ac->nodemask){if?(!zone_watermark_fast(zone,?order,?mark,?ac_classzone_idx(ac),?alloc_flags)){ret?=?node_reclaim(zone->zone_pgdat,?gfp_mask,?order);?switch?(ret)?{case?NODE_RECLAIM_NOSCAN:continue;case?NODE_RECLAIM_FULL:continue;default:if?(zone_watermark_ok(zone,?order,?mark,?ac_classzone_idx(ac),?alloc_flags))goto?try_this_zone;continue;}}try_this_zone:?//本zone正常水位page?=?rmqueue(ac->preferred_zoneref->zone,?zone,?order,?gfp_mask,?alloc_flags,?ac->migratetype);}return?NULL; }

    首先遍歷當前zone,按照HIGHMEM->NORMAL的方向進行遍歷,判斷當前zone是否能夠進行內存分配的條件是首先判斷free memory是否滿足low water mark水位值,如果不滿足則進行一次快速的內存回收操作,然后再次檢測是否滿足low water mark,如果還是不能滿足,相同步驟遍歷下一個zone,滿足的話進入正常的分配情況,即rmqueue函數,這也是伙伴系統的核心。

    Buddy 分配算法

    在看函數前,我們先看下算法,因為我一直認為有了“道”的理解才好進一步理解“術”。

    假設這是一段連續的頁框,陰影部分表示已經被使用的頁框,現在需要申請一個連續的5個頁框。這個時候,在這段內存上不能找到連續的5個空閑的頁框,就會去另一段內存上去尋找5個連續的頁框,這樣子,久而久之就形成了頁框的浪費。為了避免出現這種情況,Linux內核中引入了伙伴系統算法(Buddy system)。把所有的空閑頁框分組為11個塊鏈表,每個塊鏈表分別包含大小為1,2,4,8,16,32,64,128,256,512和1024個連續頁框的頁框塊。最大可以申請1024個連續頁框,對應4MB大小的連續內存。每個頁框塊的第一個頁框的物理地址是該塊大小的整數倍,如圖:

    假設要申請一個256個頁框的塊,先從256個頁框的鏈表中查找空閑塊,如果沒有,就去512個頁框的鏈表中找,找到了則將頁框塊分為2個256個頁框的塊,一個分配給應用,另外一個移到256個頁框的鏈表中。如果512個頁框的鏈表中仍沒有空閑塊,繼續向1024個頁框的鏈表查找,如果仍然沒有,則返回錯誤。頁框塊在釋放時,會主動將兩個連續的頁框塊合并為一個較大的頁框塊。

    從上面可以知道Buddy算法一直在對頁框做拆開合并拆開合并的動作。Buddy算法牛逼就牛逼在運用了世界上任何正整數都可以由2^n的和組成。這也是Buddy算法管理空閑頁表的本質。空閑內存的信息我們可以通過以下命令獲取:

    也可以通過echo m > /proc/sysrq-trigger來觀察buddy狀態,與/proc/buddyinfo的信息是一致的:

    Buddy 分配函數

    static?inline struct?page?*rmqueue(struct?zone?*preferred_zone,struct?zone?*zone,?unsigned?int?order,gfp_t?gfp_flags,?unsigned?int?alloc_flags,int?migratetype) {if?(likely(order?==?0))?{?//如果order=0則從pcp中分配page?=?rmqueue_pcplist(preferred_zone,?zone,?order,?gfp_flags,?migratetype);}do?{page?=?NULL;if?(alloc_flags?&?ALLOC_HARDER)?{//如果分配標志中設置了ALLOC_HARDER,則從free_list[MIGRATE_HIGHATOMIC]的鏈表中進行頁面分配page?=?__rmqueue_smallest(zone,?order,?MIGRATE_HIGHATOMIC);}if?(!page)?//前兩個條件都不滿足,則在正常的free_list[MIGRATE_*]中進行分配page?=?__rmqueue(zone,?order,?migratetype);}?while?(page?&&?check_new_pages(page,?order));...... }

    Linux分區頁框分配器之水位

    我們講頁框分配器的時候講到了快速分配和慢速分配,其中伙伴算法是在快速分配里做的,忘記的小伙伴我們再看下:

    static?struct?page?* get_page_from_freelist(gfp_t?gfp_mask,?unsigned?int?order,?int?alloc_flags,const?struct?alloc_context?*ac) {for_next_zone_zonelist_nodemask(zone,?z,?ac->zonelist,?ac->high_zoneidx,?ac->nodemask){if?(!zone_watermark_fast(zone,?order,?mark,?ac_classzone_idx(ac),?alloc_flags)){ret?=?node_reclaim(zone->zone_pgdat,?gfp_mask,?order);?switch?(ret)?{case?NODE_RECLAIM_NOSCAN:continue;case?NODE_RECLAIM_FULL:continue;default:if?(zone_watermark_ok(zone,?order,?mark,?ac_classzone_idx(ac),?alloc_flags))goto?try_this_zone;continue;}}try_this_zone:?//本zone正常水位page?=?rmqueue(ac->preferred_zoneref->zone,?zone,?order,?gfp_mask,?alloc_flags,?ac->migratetype);}return?NULL; }

    可以看到在進行伙伴算法分配前有個關于水位的判斷,今天我們就看下水位的概念。

    簡單的說在使用分區頁面分配器中會將可以用的free pages與zone里的水位(watermark)進行比較。

    水位初始化

    • nr_free_buffer_pages 是獲取ZONE_DMA和ZONE_NORMAL區中高于high水位的總頁數nr_free_buffer_pages = managed_pages - high_pages

    • min_free_kbytes 是總的min大小,min_free_kbytes = 4 * sqrt(lowmem_kbytes)

    • setup_per_zone_wmarks 根據總的min值,再加上各個zone在總內存中的占比,然后通過do_div就計算出他們各自的min值,進而計算出各個zone的水位大小。min,low,high的關系如下:low = min *125%;

    • high = min * 150%

    • min:low:high = 4:5:6

    • setup_per_zone_lowmem_reserve 當從Normal失敗后,會嘗試從DMA申請分配,通過lowmem_reserve[DMA],限制來自Normal的分配請求。其值可以通過/proc/sys/vm/lowmem_reserve_ratio來修改。

    從這張圖可以看出:

    • 如果空閑頁數目min值,則該zone非常缺頁,頁面回收壓力很大,應用程序寫內存操作就會被阻塞,直接在應用程序的進程上下文中進行回收,即direct reclaim。

    • 如果空閑頁數目小于low值,kswapd線程將被喚醒,并開始釋放回收頁面。

    • 如果空閑頁面的值大于high值,則該zone的狀態很完美, kswapd線程將重新休眠。

    Linux頁框分配器之內存碎片化整理

    什么是內存碎片化

    Linux物理內存碎片化包括兩種:內部碎片化和外部碎片化。

    • 內部碎片化:

    指分配給用戶的內存空間中未被使用的部分。例如進程需要使用3K bytes物理內存,于是向系統申請了大小等于3Kbytes的內存,但是由于Linux內核伙伴系統算法最小顆粒是4K bytes,所以分配的是4Kbytes內存,那么其中1K bytes未被使用的內存就是內存內碎片。

    • 外部碎片化:

    指系統中無法利用的小內存塊。例如系統剩余內存為16K bytes,但是這16K bytes內存是由4個4K bytes的頁面組成,即16K內存物理頁幀號#1不連續。在系統剩余16K bytes內存的情況下,系統卻無法成功分配大于4K的連續物理內存,該情況就是內存外碎片導致。

    碎片化整理算法

    Linux內存對碎片化的整理算法主要應用了內核的頁面遷移機制,是一種將可移動頁面進行遷移后騰出連續物理內存的方法。

    假設存在一個非常小的內存域如下:

    藍色表示空閑的頁面,白色表示已經被分配的頁面,可以看到如上內存域的空閑頁面(藍色)非常零散,無法分配大于兩頁的連續物理內存。

    下面演示一下內存規整的簡化工作原理,內核會運行兩個獨立的掃描動作:第一個掃描從內存域的底部開始,一邊掃描一邊將已分配的可移動(MOVABLE)頁面記錄到一個列表中:

    另外第二掃描是從內存域的頂部開始,掃描可以作為頁面遷移目標的空閑頁面位置,然后也記錄到一個列表里面:

    等兩個掃描在域中間相遇,意味著掃描結束,然后將左邊掃描得到的已分配的頁面遷移到右邊空閑的頁面中,左邊就形成了一段連續的物理內存,完成頁面規整。

    碎片化整理的三種方式

    static?struct?page?* __alloc_pages_direct_compact(gfp_t?gfp_mask,?unsigned?int?order,unsigned?int?alloc_flags,?const?struct?alloc_context?*ac,enum?compact_priority?prio,?enum?compact_result?*compact_result) {struct?page?*page;unsigned?int?noreclaim_flag;if?(!order)return?NULL;noreclaim_flag?=?memalloc_noreclaim_save();*compact_result?=?try_to_compact_pages(gfp_mask,?order,?alloc_flags,?ac,prio);memalloc_noreclaim_restore(noreclaim_flag);if?(*compact_result?<=?COMPACT_INACTIVE)return?NULL;count_vm_event(COMPACTSTALL);page?=?get_page_from_freelist(gfp_mask,?order,?alloc_flags,?ac);if?(page)?{struct?zone?*zone?=?page_zone(page);zone->compact_blockskip_flush?=?false;compaction_defer_reset(zone,?order,?true);count_vm_event(COMPACTSUCCESS);return?page;}count_vm_event(COMPACTFAIL);cond_resched();return?NULL; }

    在linux內核里一共有3種方式可以碎片化整理,我們總結如下:

    Linux slab分配器

    在Linux中,伙伴系統是以頁為單位分配內存。但是現實中很多時候卻以字節為單位,不然申請10Bytes內存還要給1頁的話就太浪費了。slab分配器就是為小內存分配而生的。slab分配器分配內存以Byte為單位。但是slab分配器并沒有脫離伙伴系統,而是基于伙伴系統分配的大內存進一步細分成小內存分配。

    他們之間的關系可以用一張圖來描述:

    流程分析

    kmem_cache_alloc 主要四步:

  • 先從 kmem_cache_cpu->freelist中分配,如果freelist為null

  • 接著去 kmem_cache_cpu->partital鏈表中分配,如果此鏈表為null

  • 接著去 kmem_cache_node->partital鏈表分配,如果此鏈表為null

  • 重新分配一個slab。

  • Linux 內存管理之vmalloc

    根據前面的系列文章,我們知道了buddy system是基于頁框分配器,kmalloc是基于slab分配器,而且這些分配的地址都是物理內存連續的。但是隨著碎片化的積累,連續物理內存的分配就會變得困難,對于那些非DMA訪問,不一定非要連續物理內存的話完全可以像malloc那樣,將不連續的物理內存頁框映射到連續的虛擬地址空間中,這就是vmap的來源)(提供把離散的page映射到連續的虛擬地址空間),vmalloc的分配就是基于這個機制來實現的。

    vmalloc最小分配一個page,并且分配到的頁面不保證是連續的,因為vmalloc內部調用alloc_page多次分配單個頁面。

    vmalloc的區域就是在上圖中VMALLOC_START - VMALLOC_END之間,可通過/proc/vmallocinfo查看。

    vmalloc流程

    主要分以下三步:

  • 從VMALLOC_START到VMALLOC_END查找空閑的虛擬地址空間(hole)

  • 根據分配的size,調用alloc_page依次分配單個頁面.

  • 把分配的單個頁面,映射到第一步中找到的連續的虛擬地址。把分配的單個頁面,映射到第一步中找到的連續的虛擬地址。

  • Linux進程的內存管理之缺頁異常

    當進程訪問這些還沒建立映射關系的虛擬地址時,處理器會自動觸發缺頁異常。

    ARM64把異常分為同步異常和異步異常,通常異步異常指的是中斷(可看《上帝視角看中斷》),同步異常指的是異常。關于ARM異常處理的文章可參考《ARMv8異常處理簡介》。

    當處理器有異常發生時,處理器會先跳轉到ARM64的異常向量表中:

    ENTRY(vectors)kernel_ventry?1,?sync_invalid???//?Synchronous?EL1tkernel_ventry?1,?irq_invalid???//?IRQ?EL1tkernel_ventry?1,?fiq_invalid???//?FIQ?EL1tkernel_ventry?1,?error_invalid??//?Error?EL1tkernel_ventry?1,?sync????//?Synchronous?EL1hkernel_ventry?1,?irq????//?IRQ?EL1hkernel_ventry?1,?fiq_invalid???//?FIQ?EL1hkernel_ventry?1,?error_invalid??//?Error?EL1hkernel_ventry?0,?sync????//?Synchronous?64-bit?EL0kernel_ventry?0,?irq????//?IRQ?64-bit?EL0kernel_ventry?0,?fiq_invalid???//?FIQ?64-bit?EL0kernel_ventry?0,?error_invalid??//?Error?64-bit?EL0#ifdef?CONFIG_COMPATkernel_ventry?0,?sync_compat,?32??//?Synchronous?32-bit?EL0kernel_ventry?0,?irq_compat,?32??//?IRQ?32-bit?EL0kernel_ventry?0,?fiq_invalid_compat,?32?//?FIQ?32-bit?EL0kernel_ventry?0,?error_invalid_compat,?32?//?Error?32-bit?EL0 #elsekernel_ventry?0,?sync_invalid,?32??//?Synchronous?32-bit?EL0kernel_ventry?0,?irq_invalid,?32??//?IRQ?32-bit?EL0kernel_ventry?0,?fiq_invalid,?32??//?FIQ?32-bit?EL0kernel_ventry?0,?error_invalid,?32??//?Error?32-bit?EL0 #endif END(vectors)

    以el1下的異常為例,當跳轉到el1_sync函數時,讀取ESR的值以判斷異常類型。根據類型跳轉到不同的處理函數里,如果是data abort的話跳轉到el1_da函數里,instruction abort的話跳轉到el1_ia函數里:

    el1_sync:kernel_entry?1mrs?x1,?esr_el1???//?read?the?syndrome?registerlsr?x24,?x1,?#ESR_ELx_EC_SHIFT?//?exception?classcmp?x24,?#ESR_ELx_EC_DABT_CUR?//?data?abort?in?EL1b.eq?el1_dacmp?x24,?#ESR_ELx_EC_IABT_CUR?//?instruction?abort?in?EL1b.eq?el1_iacmp?x24,?#ESR_ELx_EC_SYS64??//?configurable?trapb.eq?el1_undefcmp?x24,?#ESR_ELx_EC_SP_ALIGN?//?stack?alignment?exceptionb.eq?el1_sp_pccmp?x24,?#ESR_ELx_EC_PC_ALIGN?//?pc?alignment?exceptionb.eq?el1_sp_pccmp?x24,?#ESR_ELx_EC_UNKNOWN?//?unknown?exception?in?EL1b.eq?el1_undefcmp?x24,?#ESR_ELx_EC_BREAKPT_CUR?//?debug?exception?in?EL1b.ge?el1_dbgb?el1_inv

    流程圖如下:

    do_page_fault

    static?int?__do_page_fault(struct?mm_struct?*mm,?unsigned?long?addr,unsigned?int?mm_flags,?unsigned?long?vm_flags,struct?task_struct?*tsk) {struct?vm_area_struct?*vma;int?fault;vma?=?find_vma(mm,?addr);fault?=?VM_FAULT_BADMAP;?//沒有找到vma區域,說明addr還沒有在進程的地址空間中if?(unlikely(!vma))goto?out;if?(unlikely(vma->vm_start?>?addr))goto?check_stack;/**?Ok,?we?have?a?good?vm_area?for?this?memory?access,?so?we?can?handle*?it.*/ good_area://一個好的vma/**?Check?that?the?permissions?on?the?VMA?allow?for?the?fault?which*?occurred.*/if?(!(vma->vm_flags?&?vm_flags))?{//權限檢查fault?=?VM_FAULT_BADACCESS;?goto?out;}//重新建立物理頁面到VMA的映射關系return?handle_mm_fault(vma,?addr?&?PAGE_MASK,?mm_flags);check_stack:if?(vma->vm_flags?&?VM_GROWSDOWN?&&?!expand_stack(vma,?addr))goto?good_area; out:return?fault; }

    從__do_page_fault函數能看出來,當觸發異常的虛擬地址屬于某個vma,并且擁有觸發頁錯誤異常的權限時,會調用到handle_mm_fault函數來建立vma和物理地址的映射,而handle_mm_fault函數的主要邏輯是通過__handle_mm_fault來實現的。

    __handle_mm_fault

    static?int?__handle_mm_fault(struct?vm_area_struct?*vma,?unsigned?long?address,unsigned?int?flags) {......//查找頁全局目錄,獲取地址對應的表項pgd?=?pgd_offset(mm,?address);//查找頁四級目錄表項,沒有則創建p4d?=?p4d_alloc(mm,?pgd,?address);if?(!p4d)return?VM_FAULT_OOM;//查找頁上級目錄表項,沒有則創建vmf.pud?=?pud_alloc(mm,?p4d,?address);......//查找頁中級目錄表項,沒有則創建vmf.pmd?=?pmd_alloc(mm,?vmf.pud,?address);......//處理pte頁表return?handle_pte_fault(&vmf); }

    do_anonymous_page

    匿名頁缺頁異常,對于匿名映射,映射完成之后,只是獲得了一塊虛擬內存,并沒有分配物理內存,當第一次訪問的時候:

  • 如果是讀訪問,會將虛擬頁映射到0頁,以減少不必要的內存分配

  • 如果是寫訪問,用alloc_zeroed_user_highpage_movable分配新的物理頁,并用0填充,然后映射到虛擬頁上去

  • 如果是先讀后寫訪問,則會發生兩次缺頁異常:第一次是匿名頁缺頁異常的讀的處理(虛擬頁到0頁的映射),第二次是寫時復制缺頁異常處理。

  • 從上面的總結我們知道,第一次訪問匿名頁時有三種情況,其中第一種和第三種情況都會涉及到0頁。

    do_fault

    do_swap_page

    上面已經講過,pte對應的內容不為0(頁表項存在),但是pte所對應的page不在內存中時,表示此時pte的內容所對應的頁面在swap空間中,缺頁異常時會通過do_swap_page()函數來分配頁面。

    do_swap_page發生在swap in的時候,即查找磁盤上的slot,并將數據讀回。

    換入的過程如下:

  • 查找swap cache中是否存在所查找的頁面,如果存在,則根據swap cache引用的內存頁,重新映射并更新頁表;如果不存在,則分配新的內存頁,并添加到swap cache的引用中,更新內存頁內容完成后,更新頁表。

  • 換入操作結束后,對應swap area的頁引用減1,當減少到0時,代表沒有任何進程引用了該頁,可以進行回收。

  • int?do_swap_page(struct?vm_fault?*vmf) {......//根據pte找到swap?entry,?swap?entry和pte有一個對應關系entry?=?pte_to_swp_entry(vmf->orig_pte);......if?(!page)//根據entry從swap緩存中查找頁,?在swapcache里面尋找entry對應的page//Lookup?a?swap?entry?in?the?swap?cachepage?=?lookup_swap_cache(entry,?vma_readahead???vma?:?NULL,vmf->address);//沒有找到頁if?(!page)?{if?(vma_readahead)page?=?do_swap_page_readahead(entry,GFP_HIGHUSER_MOVABLE,?vmf,?&swap_ra);else//如果swapcache里面找不到就在swap?area里面找,分配新的內存頁并從swap?area中讀入page?=?swapin_readahead(entry,GFP_HIGHUSER_MOVABLE,?vma,?vmf->address);......//獲取一個pte的entry,重新建立映射vmf->pte?=?pte_offset_map_lock(vma->vm_mm,?vmf->pmd,?vmf->address,&vmf->ptl);......//anonpage數加1,匿名頁從swap空間交換出來,所以加1//swap?page個數減1,由page和VMA屬性創建一個新的pteinc_mm_counter_fast(vma->vm_mm,?MM_ANONPAGES);dec_mm_counter_fast(vma->vm_mm,?MM_SWAPENTS);pte?=?mk_pte(page,?vma->vm_page_prot);......flush_icache_page(vma,?page);if?(pte_swp_soft_dirty(vmf->orig_pte))pte?=?pte_mksoft_dirty(pte);//將新生成的PTE?entry添加到硬件頁表中set_pte_at(vma->vm_mm,?vmf->address,?vmf->pte,?pte);vmf->orig_pte?=?pte;//根據page是否為swapcacheif?(page?==?swapcache)?{//如果是,將swap緩存頁用作anon頁,添加反向映射rmap中do_page_add_anon_rmap(page,?vma,?vmf->address,?exclusive);mem_cgroup_commit_charge(page,?memcg,?true,?false);//并添加到active鏈表中activate_page(page);//如果不是}?else?{?/*?ksm?created?a?completely?new?copy?*///使用新頁面并復制swap緩存頁,添加反向映射rmap中page_add_new_anon_rmap(page,?vma,?vmf->address,?false);mem_cgroup_commit_charge(page,?memcg,?false,?false);//并添加到lru鏈表中lru_cache_add_active_or_unevictable(page,?vma);}//釋放swap?entryswap_free(entry);......if?(vmf->flags?&?FAULT_FLAG_WRITE)?{//有寫請求則寫時復制ret?|=?do_wp_page(vmf);if?(ret?&?VM_FAULT_ERROR)ret?&=?VM_FAULT_ERROR;goto?out;}......return?ret; }

    do_wp_page

    走到這里說明頁面在內存中,只是PTE只有讀權限,而又要寫內存的時候就會觸發do_wp_page。

    do_wp_page函數用于處理寫時復制(copy on write),其流程比較簡單,主要是分配新的物理頁,拷貝原來頁的內容到新頁,然后修改頁表項內容指向新頁并修改為可寫(vma具備可寫屬性)。

    static?int?do_wp_page(struct?vm_fault?*vmf)__releases(vmf->ptl) {struct?vm_area_struct?*vma?=?vmf->vma;//從頁表項中得到頁幀號,再得到頁描述符,發生異常時地址所在的page結構vmf->page?=?vm_normal_page(vma,?vmf->address,?vmf->orig_pte);if?(!vmf->page)?{//沒有page結構是使用頁幀號的特殊映射/**?VM_MIXEDMAP?!pfn_valid()?case,?or?VM_SOFTDIRTY?clear?on?a*?VM_PFNMAP?VMA.**?We?should?not?cow?pages?in?a?shared?writeable?mapping.*?Just?mark?the?pages?writable?and/or?call?ops->pfn_mkwrite.*/if?((vma->vm_flags?&?(VM_WRITE|VM_SHARED))?==(VM_WRITE|VM_SHARED))//處理共享可寫映射return?wp_pfn_shared(vmf);pte_unmap_unlock(vmf->pte,?vmf->ptl);//處理私有可寫映射return?wp_page_copy(vmf);}/**?Take?out?anonymous?pages?first,?anonymous?shared?vmas?are*?not?dirty?accountable.*/if?(PageAnon(vmf->page)?&&?!PageKsm(vmf->page))?{int?total_map_swapcount;if?(!trylock_page(vmf->page))?{//添加原來頁的引用計數,方式被釋放get_page(vmf->page);//釋放頁表鎖pte_unmap_unlock(vmf->pte,?vmf->ptl);lock_page(vmf->page);vmf->pte?=?pte_offset_map_lock(vma->vm_mm,?vmf->pmd,vmf->address,?&vmf->ptl);if?(!pte_same(*vmf->pte,?vmf->orig_pte))?{unlock_page(vmf->page);pte_unmap_unlock(vmf->pte,?vmf->ptl);put_page(vmf->page);return?0;}put_page(vmf->page);}//單身匿名頁面的處理if?(reuse_swap_page(vmf->page,?&total_map_swapcount))?{if?(total_map_swapcount?==?1)?{/**?The?page?is?all?ours.?Move?it?to*?our?anon_vma?so?the?rmap?code?will*?not?search?our?parent?or?siblings.*?Protected?against?the?rmap?code?by*?the?page?lock.*/page_move_anon_rmap(vmf->page,?vma);}unlock_page(vmf->page);wp_page_reuse(vmf);return?VM_FAULT_WRITE;}unlock_page(vmf->page);}?else?if?(unlikely((vma->vm_flags?&?(VM_WRITE|VM_SHARED))?==(VM_WRITE|VM_SHARED)))?{//共享可寫,不需要復制物理頁,設置頁表權限即可return?wp_page_shared(vmf);}/**?Ok,?we?need?to?copy.?Oh,?well..*/get_page(vmf->page);pte_unmap_unlock(vmf->pte,?vmf->ptl);//私有可寫,復制物理頁,將虛擬頁映射到物理頁return?wp_page_copy(vmf); }

    Linux 內存管理之CMA

    CMA是reserved的一塊內存,用于分配連續的大塊內存。當設備驅動不用時,內存管理系統將該區域用于分配和管理可移動類型頁面;當設備驅動使用時,此時已經分配的頁面需要進行遷移,又用于連續內存分配;其用法與DMA子系統結合在一起充當DMA的后端,具體可參考《沒有IOMMU的DMA操作》。

    CMA區域 cma_areas 的創建

    CMA區域的創建有兩種方法,一種是通過dts的reserved memory,另外一種是通過command line參數和內核配置參數。

    • dts方式:

    reserved-memory?{/*?global?autoconfigured?region?for?contiguous?allocations?*/linux,cma?{compatible?=?"shared-dma-pool";reusable;size?=?<0?0x28000000>;alloc-ranges?=?<0?0xa0000000?0?0x40000000>;linux,cma-default;}; };

    device tree中可以包含reserved-memory node,系統啟動的時候會打開rmem_cma_setup

    RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);

    • command line方式:cma=nn[MG]@[start[MG][-end[MG]]]

    static?int?__init?early_cma(char?*p) {pr_debug("%s(%s)\n",?__func__,?p);size_cmdline?=?memparse(p,?&p);if?(*p?!=?'@')?{/*if?base?and?limit?are?not?assigned,set?limit?to?high?memory?bondary?to?use?low?memory.*/limit_cmdline?=?__pa(high_memory);return?0;}base_cmdline?=?memparse(p?+?1,?&p);if?(*p?!=?'-')?{limit_cmdline?=?base_cmdline?+?size_cmdline;return?0;}limit_cmdline?=?memparse(p?+?1,?&p);return?0; } early_param("cma",?early_cma);

    系統在啟動的過程中會把cmdline里的nn, start, end傳給函數dma_contiguous_reserve,流程如下:

    setup_arch--->arm64_memblock_init--->dma_contiguous_reserve->dma_contiguous_reserve_area->cma_declare_contiguous

    將CMA區域添加到Buddy System

    為了避免這塊reserved的內存在不用時候的浪費,內存管理模塊會將CMA區域添加到Buddy System中,用于可移動頁面的分配和管理。CMA區域是通過cma_init_reserved_areas接口來添加到Buddy System中的。

    static?int?__init?cma_init_reserved_areas(void) {int?i;for?(i?=?0;?i?<?cma_area_count;?i++)?{int?ret?=?cma_activate_area(&cma_areas[i]);if?(ret)return?ret;}return?0; } core_initcall(cma_init_reserved_areas);

    其實現比較簡單,主要分為兩步:

  • 把該頁面設置為MIGRATE_CMA標志

  • 通過__free_pages將頁面添加到buddy system中

  • CMA分配

    《沒有IOMMU的DMA操作》里講過,CMA是通過cma_alloc分配的。cma_alloc->alloc_contig_range(..., MIGRATE_CMA,...),向剛才釋放給buddy system的MIGRATE_CMA類型頁面,重新“收集”過來。

    用CMA的時候有一點需要注意:

    也就是上圖中黃色部分的判斷。CMA內存在分配過程是一個比較“重”的操作,可能涉及頁面遷移、頁面回收等操作,因此不適合用于atomic context。比如之前遇到過一個問題,當內存不足的情況下,向U盤寫數據的同時操作界面會出現卡頓的現象,這是因為CMA在遷移的過程中需要等待當前頁面中的數據回寫到U盤之后,才會進一步的規整為連續內存供gpu/display使用,從而出現卡頓的現象。

    總結

    至此,從CPU開始訪問內存,到物理頁的劃分,再到內核頁框分配器的實現,以及slab分配器的實現,最后到CMA等連續內存的使用,把Linux內存管理的知識串了起來,算是形成了整個閉環。相信如果掌握了本篇內容,肯定打開了Linux內核的大門,有了這個基石,祝愿大家接下來的內核學習越來越輕松。

    ?

    ?

    ?記得點擊分享在看

    總結

    以上是生活随笔為你收集整理的万字整理,图解Linux内存管理所有知识点的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    99在线观看免费视频精品观看 | 99麻豆久久久国产精品免费 | 九色精品免费永久在线 | 婷婷丁香花五月天 | 999在线观看视频 | 在线影院 国内精品 | 91福利区一区二区三区 | 亚洲视频久久久 | 草久在线观看视频 | 久久久久一区二区三区 | 亚洲少妇自拍 | 伊人手机在线 | 韩国av免费观看 | 免费看污黄网站 | 日韩在线激情 | 日韩色综合 | 狠狠88综合久久久久综合网 | a√国产免费a | 国产在线观看不卡 | 字幕网在线观看 | 香蕉精品视频在线观看 | 97色噜噜 | 久久精品一区二区三区视频 | 久久综合中文字幕 | 国产精品理论片在线观看 | 中文字幕在线观看免费观看 | 日韩成人不卡 | 久草久视频 | 蜜桃麻豆www久久囤产精品 | 亚洲人天堂 | 国产精品成人一区二区三区吃奶 | 亚洲成人午夜在线 | 国产又粗又长又硬免费视频 | 亚洲精品一区二区久 | 中文字幕成人一区 | 最新国产精品视频 | 91系列在线 | 久久久国产精品一区二区三区 | 美女网站免费福利视频 | 午夜视频一区二区 | 六月丁香激情网 | 国产欧美日韩视频 | 亚洲a网| 午夜精品av | 处女av在线 | 国产成人久久精品77777综合 | 天天色天 | 国产网红在线观看 | 日本黄色大片儿 | 久久久久久久久久久久久久电影 | 欧美大片大全 | 最近中文字幕国语免费高清6 | 91麻豆精品国产自产在线 | 美女激情影院 | 欧美精品xxx | 色偷偷人人澡久久超碰69 | 91精彩在线视频 | 亚洲成av人片在线观看香蕉 | 免费黄色av| 伊人久久电影网 | 91久久偷偷做嫩草影院 | 精品国产乱码一区二区三区在线 | 黄色三级在线 | 黄色资源在线观看 | 国产在线国偷精品产拍 | 免费在线观看中文字幕 | 日韩特级黄色片 | 欧美一区二区在线免费观看 | 免费高清国产 | 特黄色大片 | 国产二级视频 | 亚洲天堂视频在线 | caobi视频 | 伊人影院在线观看 | 亚洲成人资源在线观看 | 国产欧美精品xxxx另类 | 视频一区二区免费 | 久久不色 | 中文字幕高清在线 | 国产精品中文久久久久久久 | 97超碰人人澡 | 欧美亚洲国产精品久久高清浪潮 | 久草爱| 91av在线免费看| 国产成人av电影在线观看 | 五月天久久激情 | 亚洲成人午夜在线 | 精品91久久久久 | 精品久久一区 | 黄色免费高清视频 | 日韩av电影中文字幕在线观看 | 国产又黄又猛又粗 | 日韩亚洲精品电影 | 国产91在线观| 国产一二三在线视频 | 亚洲伊人成综合网 | 深爱激情久久 | 四虎最新入口 | 在线观看一 | 国产精品久久久久久久久久久杏吧 | 激情在线网址 | 欧美国产精品一区二区 | 91精品黄色 | 亚洲天堂精品视频 | 91精品国产九九九久久久亚洲 | 伊人五月天综合 | 国产一区欧美二区 | 欧美另类人妖 | 亚洲国产精品久久久 | 久草香蕉在线 | 亚洲日本色 | 午夜久久影院 | 婷婷深爱五月 | 绯色av一区 | 97精品久久| 综合激情av| 国精产品永久999 | 视频在线亚洲 | 日韩av一区二区在线 | 天天操天天操天天操天天操天天操天天操 | 五月婷婷伊人网 | 精品xxx| 欧美精品久久天天躁 | 亚洲免费av在线 | 婷五月激情 | 白丝av免费观看 | 在线电影中文字幕 | 又黄又爽又无遮挡免费的网站 | 在线观看电影av | 国产二级视频 | 男女日麻批 | 91精品黄色 | 九九热在线精品 | 久热精品国产 | 99久久er热在这里只有精品66 | 国产精品地址 | 激情婷婷久久 | 国产视频一区二区在线 | 中文字幕日韩电影 | 操操日| 久久久精品综合 | 国产精品久久久久一区二区三区共 | 久久久久二区 | 亚洲一级电影在线观看 | 97品白浆高清久久久久久 | 亚洲国产一区二区精品专区 | 国产成人精品亚洲精品 | 91最新在线 | 久久96 | 色wwww| 国产1区2区3区精品美女 | 久久天天躁夜夜躁狠狠躁2022 | 亚洲成人av在线电影 | 日韩精品一区二区不卡 | 亚洲三级精品 | 99国产精品久久久久久久久久 | 国产精品美女久久久久久久久 | 国产中文字幕一区二区三区 | 日本久久高清视频 | 欧美男同网站 | 久久这里只有精品23 | 在线成人中文字幕 | 亚洲在线精品 | 亚洲资源在线网 | 中文在线www| 国产免费一区二区三区网站免费 | 国产高清成人在线 | 91人人爱| 四虎海外影库www4hu | 国产亚洲婷婷 | 九九九国产 | 久久99国产一区二区三区 | 国产精品久久久久久久久久久久午夜 | 欧美成人亚洲 | 77国产精品 | 久草精品视频在线看网站免费 | 西西人体www444 | 91大神视频网站 | 视频一区二区视频 | a国产精品| 久久久精品成人 | 免费a v观看| 天天想夜夜操 | 天天摸天天干天天操天天射 | 国产小视频免费观看 | 爱射综合 | 开心激情综合网 | 久久久九色精品国产一区二区三区 | 国产精品一区二区av日韩在线 | 国产中文字幕视频在线 | 国产高清一区二区 | 日韩免费一级电影 | 久久1电影院 | 亚洲dvd| www.日日日.com| 美女天天操 | 91在线色 | 一级性av| 日韩美女黄色片 | 韩国一区二区在线观看 | 久久这里只有精品1 | 久久久久9999亚洲精品 | 91免费国产在线观看 | 在线免费看片 | 国产精品va在线观看入 | 日韩精品久久中文字幕 | 亚洲女在线 | 91精品国产综合久久福利 | 激情五月播播久久久精品 | 成人黄色电影免费观看 | 久久er99热精品一区二区 | 9992tv成人免费看片 | 欧美午夜一区二区福利视频 | 欧美另类交人妖 | 91完整视频 | 91九色自拍 | 女人18毛片a级毛片一区二区 | 国产亚洲精品久久久久久久久久久久 | 国产成人精品日本亚洲999 | 97人人模人人爽人人喊中文字 | 九九热免费视频在线观看 | 天天操夜夜操 | 亚洲综合涩 | 成片人卡1卡2卡3手机免费看 | 精品国产区在线 | 五月婷婷天堂 | 久久婷婷影视 | 久久久久久毛片精品免费不卡 | 丁香综合激情 | 亚洲国产三级在线观看 | 久久伊人国产精品 | 激情丁香久久 | 香蕉视频18 | 国产精品久久久精品 | 久草在线综合 | 久热久草在线 | 亚洲全部视频 | 国产精品99在线播放 | 亚洲国产精品传媒在线观看 | 久久精品视频网址 | 国产专区在线 | 欧洲激情综合 | 国产精品1区2区3区 久久免费视频7 | 久久专区| 日韩视频一区二区在线观看 | 亚洲人成人在线 | 97国产精品久久 | 在线看岛国av | 日本中文字幕视频 | 麻豆成人在线观看 | 精品久久久久久久久亚洲 | 91精品爽啪蜜夜国产在线播放 | 色吧久久 | 毛片二区| 99久久电影 | 国产一区免费在线 | 亚洲播播| 午夜影院一级 | 99久久www免费| 亚洲精品美女久久久久 | 在线观看黄色的网站 | 天天操月月操 | 亚洲成人家庭影院 | 色综合天天色综合 | 日韩成人一级大片 | 在线观看视频国产 | 在线观看视频你懂得 | 国内成人精品视频 | 亚洲va在线va天堂va偷拍 | 久久久久国产精品一区二区 | 超碰在线免费97 | 香蕉在线观看视频 | 国产人成在线观看 | 久久久久久久久久久综合 | 久久综合中文色婷婷 | 91cn国产在线 | 97超碰中文 | 久久私人影院 | 91福利社区在线观看 | 日韩成人av在线 | 天天干天天色2020 | 午夜精品久久久久久中宇69 | 一区二区三区四区五区在线 | 国产区精品区 | 99国产在线观看 | 久久99国产综合精品 | 操久在线 | 亚洲九九| 97精品国自产拍在线观看 | 91激情视频在线播放 | av免费黄色 | 超碰97免费观看 | 国产91学生粉嫩喷水 | 国产高清免费在线播放 | 国产精品资源在线观看 | 久久老司机精品视频 | 日日干天天 | 狠狠狠狠狠色综合 | 欧美激情视频一二区 | 久久久久国产a免费观看rela | 国产亚洲精品久久久久久久久久 | 中文字幕中文字幕 | 国产亚洲成av片在线观看 | 精品久久久久久久久久岛国gif | 日本最大色倩网站www | 国产精品精品国产婷婷这里av | 在线精品一区二区 | 99r精品视频在线观看 | 免费麻豆视频 | 超级av在线 | 九九久久免费视频 | 精品美女在线视频 | 免费高清在线一区 | 一区久久久 | 91手机电视 | 久久视频99 | 午夜精品久久久久久久久久久久久久 | 蜜臀久久99精品久久久久久网站 | 亚洲精品国产第一综合99久久 | 亚洲国产视频直播 | 日韩视频1 | 在线 国产一区 | 日韩免费高清在线 | 久久久免费播放 | 激情开心站| 日韩久久久久久久久 | av免费网页 | 超碰人人舔 | 日日干夜夜操视频 | 欧美性受极品xxxx喷水 | 成 人 免费 黄 色 视频 | 国产成人不卡 | 在线黄av| 91黄色在线视频 | 午夜精品导航 | 欧美日韩一区二区三区在线观看视频 | 欧美日韩精品区 | 7777精品伊人久久久大香线蕉 | 久久免费视频这里只有精品 | 国产中文字幕网 | 久久99国产综合精品免费 | 99国内精品久久久久久久 | 国产精品自产拍在线观看蜜 | 国产精品一区二区免费视频 | 久久99这里只有精品 | 一区 二区电影免费在线观看 | 永久免费视频国产 | 超碰人人超碰 | 午夜精品一区二区三区四区 | www久久99| 91免费的视频在线播放 | av高清一区二区三区 | 丁香激情综合久久伊人久久 | 国产一级特黄电影 | 天天拍天天色 | 日韩国产精品一区 | 91超级碰| 在线观看视频黄 | 午夜精品久久久久久久99水蜜桃 | 国产一二区视频 | 一级片视频在线 | 免费的国产精品 | 国产一级在线观看 | 激情五月亚洲 | 玖玖爱在线观看 | 亚洲欧美激情精品一区二区 | 中文字幕在线网址 | 五月天久久激情 | 国产99久久久精品 | 国产精彩在线视频 | 中文字幕在线观看视频网站 | 久久婷婷一区二区三区 | 九热精品 | 欧美精品天堂 | 亚洲精品午夜久久久久久久久久久 | 日韩久久久久久久久久久久 | 日韩动漫免费观看高清完整版在线观看 | 亚洲激情综合 | 国产视频观看 | 97精品国产97久久久久久免费 | 成人午夜剧场在线观看 | 国产高清av在线播放 | 99国产情侣在线播放 | 成av人电影| 久久婷婷国产色一区二区三区 | 日韩免费看的电影 | 奇米四色影狠狠爱7777 | 欧美激情在线网站 | 五月婷婷中文字幕 | 久久久久久久久久久久久久免费看 | 欧美另类xxx | 亚洲激情一区二区三区 | 免费看一级一片 | 国产美女网站视频 | 久久人91精品久久久久久不卡 | 久久国产午夜精品理论片最新版本 | 国产精品久久久毛片 | 96亚洲精品久久久蜜桃 | 亚洲精品一区二区在线观看 | 手机成人av | 超碰999 | av五月婷婷 | 中文字幕高清在线播放 | 国产免费黄色 | 悠悠av资源片 | 国产高清在线a视频大全 | av久久久| 亚洲视频六区 | 天天干天天操天天拍 | 国产亚洲人成网站在线观看 | 日韩视频中文 | 亚洲3级 | 免费黄在线看 | 激情综合色综合久久 | 女人18毛片a级毛片一区二区 | 国产精品黑丝在线观看 | 免费一级日韩欧美性大片 | 91亚洲精品久久久蜜桃 | 欧美成年人在线观看 | 99久久综合狠狠综合久久 | 久久中文精品视频 | 国产剧情在线一区 | 久久99最新地址 | 欧美精品在线观看免费 | 三上悠亚一区二区在线观看 | 亚洲精品免费在线 | 精品国产乱码久久久久久天美 | 中文字幕在线播放第一页 | 日韩久久精品一区二区 | 欧美日比视频 | 日日摸日日添夜夜爽97 | 涩涩网站在线看 | 亚洲在线| 黄色亚洲片 | 日日干天天 | 美女免费电影 | 在线播放日韩 | 中文在线字幕观看电影 | 日韩av一区在线观看 | 国产精品一区二区免费视频 | 成人网中文字幕 | 免费亚洲视频 | 成人久久久久久久久 | jizz欧美性9| 久久这里只有精品首页 | 午夜精品av | 天天草天天干天天 | 精品久久网 | 国产精品免费久久久久久久久久中文 | 成人在线视频网 | 国产精品久久久免费看 | 国产精品美女免费视频 | 日韩欧美一区二区三区视频 | 99精品视频在线看 | 久久国产热 | 91在线精品一区二区 | 国产99久久久欧美黑人 | 亚洲国产中文字幕在线视频综合 | 天天综合精品 | 在线观看视频在线观看 | 91网在线看 | 欧美精品国产综合久久 | 日日夜精品 | 99久久精品国产亚洲 | 久久中文字幕在线视频 | 亚洲91精品| 亚洲免费专区 | 国产精品久久精品 | 国产原创av在线 | 精品不卡视频 | 免费在线观看国产精品 | 免费黄色看片 | 久久久久久久久久久电影 | 亚洲h在线播放在线观看h | a视频免费看| 超碰国产在线 | 手机色站 | 国产一级精品绿帽视频 | 中文字幕91视频 | 久草青青在线观看 | 天天天天天天天操 | 久久久久久久久久久免费 | 久久久免费观看完整版 | 久草在线99 | 日韩在线视频网址 | 看av在线 | 99久久精品午夜一区二区小说 | 亚洲理论电影网 | 91探花国产综合在线精品 | 亚洲最大成人网4388xx | 亚洲成a人片在线www | 蜜桃视频在线视频 | 亚洲永久精品一区 | 欧美视频网址 | 99精品一区 | 伊人电影天堂 | 操久久网| 久久久黄色免费网站 | 亚洲黄色免费 | 国产色一区| 国产二区免费视频 | 国产精品成人一区二区三区 | 激情网色 | 人人插人人射 | 欧美日韩视频免费 | 中文字幕第一页在线视频 | 成人av视屏 | 国产精品一区二区麻豆 | 中文字幕国产一区二区 | 欧美精品一区二区免费 | 成人h在线播放 | 97免费中文视频在线观看 | 亚洲视频专区在线 | 国产精品美女久久久久久网站 | 国产精品久久三 | 五月婷婷中文字幕 | 国产精品成人免费一区久久羞羞 | 久草在线观看视频免费 | 精品色综合| 久久亚洲精品电影 | 欧美黑人性爽 | 97精品国产aⅴ | 日韩欧美精品在线观看视频 | 日韩成人av在线 | 免费99视频 | 九色91在线| 国产精品短视频 | 日韩欧美99 | 久久久久www | 中文字幕a∨在线乱码免费看 | 91在线播放综合 | 免费观看9x视频网站在线观看 | 久久免费a| 免费看成年人 | 超碰在线日本 | 久久激五月天综合精品 | 性色av香蕉一区二区 | 91九色在线视频 | 久久夜视频 | 91禁在线看 | 成人欧美亚洲 | 91日韩在线视频 | 国产对白av | 一区二区三区在线视频观看58 | 日韩精品一区二区三区免费观看 | 在线亚洲人成电影网站色www | 久久久久久久久黄色 | 国产精品免费不 | 久久国内精品99久久6app | 天天色天天干天天 | 91中文字幕网| 日韩精品第1页 | 伊人五月 | 久久免费公开视频 | 国产精品视频一二三 | 伊人五月在线 | 欧美日本不卡高清 | 成年人在线免费看视频 | 香蕉手机在线 | 97在线看| 青春草国产视频 | 中文字幕在线影视资源 | 欧美精品999 | 日本性动态图 | 中文字幕日韩国产 | 日韩美一区二区三区 | 国产精品2019 | 亚洲精品动漫成人3d无尽在线 | 欧美日韩另类在线 | 亚洲一区 av| 亚洲乱码国产乱码精品天美传媒 | 国产精品一区二区三区电影 | 国产日韩亚洲 | 国产免费成人av | 国产精品亚洲a | 日韩电影久久久 | 夜色资源站wwwcom | 精品久久久久久久久久久院品网 | 蜜臀av性久久久久蜜臀aⅴ流畅 | 国产精品毛片久久久久久久久久99999999 | 日韩最新在线 | 在线视频日韩精品 | 五月天婷亚洲天综合网鲁鲁鲁 | 午夜av在线电影 | 久草在在线视频 | 亚洲午夜精品久久久 | 亚洲精品五月天 | 亚洲国产无 | 欧美午夜性生活 | 在线观看成人一级片 | 超碰人人在 | 天天综合色天天综合 | 黄网站色欧美视频 | 国产在线播放一区 | 国产精品观看在线亚洲人成网 | 精品91在线 | 美女网站视频久久 | 91视频首页| 日韩在线视频精品 | 欧美日韩国产伦理 | 亚洲视频在线免费看 | 996久久国产精品线观看 | 91福利视频一区 | 蜜臀久久99静品久久久久久 | 中文字幕免费久久 | 久久久国产精品人人片99精片欧美一 | 久久久 精品 | 国产精品网在线观看 | www.福利 | 国产一区二区中文字幕 | 精品国产乱码久久久久久1区2匹 | 精品久久久久久综合 | 激情视频免费观看 | 天天爱天天操天天射 | 国产精品毛片一区 | 久久午夜剧场 | 91福利在线导航 | 日韩精品影视 | 一级片视频免费观看 | 六月激情丁香 | 成人在线播放免费观看 | 色综合咪咪久久网 | 四川妇女搡bbbb搡bbbb搡 | 免费看久久 | 日本不卡一区二区三区在线观看 | 日本最新中文字幕 | 亚洲精品视频观看 | 在线国产小视频 | 久久久久久久久久久久久久av | 久久av免费电影 | 一区二区三区三区在线 | av网站手机在线观看 | 国产精品视频内 | 深夜福利视频在线观看 | 天天干夜夜爱 | 亚洲欧美成人在线 | 国产午夜精品一区二区三区欧美 | 成人a在线观看高清电影 | 91资源在线播放 | 国产一级不卡视频 | 人人干97 | 精品一区免费 | 成人在线视频你懂的 | 久久大片网站 | 超碰在线人人97 | 特级毛片在线 | 中文字幕在线播放一区二区 | 久久99久久精品 | 中文字幕影片免费在线观看 | 黄av免费 | 久草免费在线观看视频 | 欧美日韩在线视频观看 | 69xx视频 | 亚洲激情免费 | 日本久久综合视频 | 日韩黄色中文字幕 | 欧美男男tv网站 | 久久精品这里都是精品 | 中文字幕免费在线 | 久久免费a | 久久免费视频5 | 天堂va欧美va亚洲va老司机 | a级国产乱理论片在线观看 伊人宗合网 | 日韩av中文字幕在线 | 毛片一二区 | 国产一区二区在线观看免费 | av在线看片 | 成人免费中文字幕 | av大全在线观看 | 欧美成a人片在线观看久 | 精品久久久久国产 | 六月丁香在线视频 | 日韩欧美在线观看一区 | 久久久精品网 | 成人啊 v| 久久综合欧美精品亚洲一区 | 伊甸园av在线 | 久久久久国 | 久久久男人的天堂 | 日韩欧美视频在线观看免费 | 曰韩精品 | 97人人看 | 久久一线 | 日韩a级黄色片 | 99av在线视频 | 午夜美女影院 | 免费看黄色91 | 色午夜| 91视频午夜 | 久久精品国产免费看久久精品 | 久久国产精品视频观看 | 亚洲精品影视在线观看 | 日韩免费视频网站 | 国产美女网站视频 | a色网站| 精品国自产在线观看 | 国产激情久久久 | 99国产视频在线 | 国产精品mv在线观看 | 色狠狠狠 | 偷拍区另类综合在线 | 色久综合| 久久香蕉国产精品麻豆粉嫩av | 日本黄色免费在线观看 | 欧美日韩国产一区二区三区在线观看 | 不卡av电影在线 | 国产视频观看 | 九色91福利 | 国产精品21区 | 亚洲人成网站精品片在线观看 | 天天摸日日操 | 美女视频黄免费的久久 | 亚洲美女精品 | 亚洲精品国产片 | av手机在线播放 | 国产视频2区 | 一区二区欧美日韩 | 天天爽天天爽夜夜爽 | 国产精品亚洲a | 欧美性护士 | 婷婷网址 | av视屏在线播放 | 日韩大片在线免费观看 | 国产免费观看高清完整版 | 色欧美视频 | 美女黄频视频大全 | 国产精品乱码一区二区视频 | www.狠狠操 | 久久av在线 | 亚洲免费av在线播放 | 中文字幕日韩精品有码视频 | 国产一级视频免费看 | 久久久精品欧美 | 日本久久99 | 亚洲久草在线视频 | av在线电影网站 | 亚洲三级性片 | 999男人的天堂 | 亚洲成人午夜av | 在线导航福利 | 探花视频免费在线观看 | 伊人婷婷在线 | 午夜手机电影 | 懂色av懂色av粉嫩av分享吧 | 亚洲精品乱码久久久久久写真 | 午夜精品福利一区二区三区蜜桃 | 在线免费观看视频a | 国产打女人屁股调教97 | 精品久久网 | 精品日韩av | 综合亚洲视频 | 国产成人精品在线观看 | 不卡av电影在线 | 久草在线免费电影 | 三级在线国产 | 亚洲午夜大片 | 欧美日韩国产精品一区二区亚洲 | 国产精品高潮呻吟久久久久 | 91激情视频在线观看 | 久久精品1区 | 福利一区二区 | 91视频免费网址 | 一区二区网 | 国产美女精品视频免费观看 | 久久福利国产 | 91资源在线 | 福利精品在线 | 国产黄大片在线观看 | 五月婷婷丁香激情 | 中文字幕视频三区 | 伊人久久精品久久亚洲一区 | 九色91在线视频 | 波多野结衣动态图 | 成人全视频免费观看在线看 | 国产91在线免费视频 | 日日草av| 超碰最新网址 | 91在线看视频免费 | 深爱开心激情网 | 亚洲特级片 | 中文字幕a在线 | 国产精品视屏 | 一区二区国产精品 | 欧美一级xxxx | 午夜aaaa| 91免费在线看片 | 91精品国产自产在线观看永久 | 国产视频每日更新 | 欧美日韩亚洲第一 | 日韩精品一区二区电影 | 新av在线| 99久久精品无码一区二区毛片 | 国产视频一区在线免费观看 | 中文字幕在线看视频 | 福利视频| 欧美黑人性爽 | av免费网页| 骄小bbw搡bbbb揉bbbb | 美女很黄免费网站 | 91麻豆产精品久久久久久 | www.黄色片网站 | 高清免费av在线 | 国产专区一 | av在线网站大全 | 久久久福利影院 | 精品自拍av | 狠狠的干狠狠的操 | 日日夜夜精品免费 | 成人资源在线观看 | 91视频久久久久 | 亚洲国产日韩精品 | 开心丁香婷婷深爱五月 | 日韩午夜小视频 | 在线观看视频在线观看 | 福利av在线| 国产精品激情在线观看 | 国产精品久久久久一区 | 亚洲天堂在线观看完整版 | av高清一区二区三区 | 成人精品电影 | 精品视频在线看 | 国产精品99久久久久久久久久久久 | 久久麻豆精品 | 成人免费视频网站在线观看 | 久久中文精品视频 | 日韩毛片在线播放 | 国产精品一区二区免费在线观看 | 国产护士hd高朝护士1 | 在线精品一区二区 | 丁香免费视频 | 亚洲欧美国产精品 | 久久精品久久久久电影 | 一区二区高清在线 | 久久99精品久久久久久久久久久久 | 国产91免费观看 | 国产一级不卡毛片 | 欧美一级免费片 | 91在线永久 | 亚洲综合一区二区精品导航 | 91在线免费观看国产 | 国产在线观看免费 | 国产一二区视频 | 7777xxxx | 99精品在线直播 | 在线一区观看 | 激情综合网五月激情 | 久久精品1区2区 | 国产精品久久久久久久婷婷 | 国产精品嫩草影视久久久 | 国产午夜精品久久 | 久久成人人人人精品欧 | 中文字幕在线看视频国产 | 国产xx视频 | 天天干天天操天天 | 麻豆va一区二区三区久久浪 | 国产精品高潮呻吟久久av无 | 国产视频一级 | 午夜精品视频免费在线观看 | 美女网站在线观看 | 少妇按摩av | 在线va视频 | 很污的网站 | 久久视频国产 | 在线黄网站 | 蜜臀av夜夜澡人人爽人人桃色 | 日韩欧美大片免费观看 | 日韩av电影手机在线观看 | 亚洲欧美日韩国产一区二区三区 | 日批网站在线观看 | 狠日日| 国产精品嫩草55av | 九九热在线免费观看 | 免费观看性生交 | 伊人伊成久久人综合网站 | 片网站 | 91视频免费网址 | 在线亚洲观看 | 国产97在线视频 | 91精品久久久久久综合乱菊 | 午夜久久久久久久 | 国产精品成人免费精品自在线观看 | 亚洲 欧美 国产 va在线影院 | 五月天综合婷婷 | 亚洲精品动漫成人3d无尽在线 | 在线视频观看亚洲 | 日韩高清精品免费观看 | 天天操天天干天天爽 | 免费国产在线精品 | 亚洲视频免费 | 精品在线观看一区二区 | 一级精品视频在线观看宜春院 | 久久综合九色综合97婷婷女人 | 少妇高潮冒白浆 | 日韩欧美在线视频一区二区三区 | 日本性动态图 | av在线播放一区二区三区 | 六月婷婷网 | 日日射av| 日韩欧美视频 | 99久久久久久久久久 | 夜夜操天天操 | 在线观看免费版高清版 | 天天爱天天射天天干天天 | 日韩久久一区 | 91人人揉日日捏人人看 | 亚洲一区二区三区毛片 | 国产在线播放一区二区三区 | 美女视频黄色免费 | 成人免费看片98欧美 | 激情丁香综合五月 | 国产精品久久久久久久久久了 | 在线观看视频你懂得 | 久久国产露脸精品国产 | 97超碰超碰 | 99视频 | 97在线视 | 欧美日韩国产免费视频 | 伊人色综合网 | 久久久影院官网 | 久久久99精品免费观看 | av网站在线免费观看 | 美女黄网站视频免费 | 韩国视频一区二区三区 | 婷婷亚洲综合五月天小说 | 在线免费观看视频一区二区三区 | 亚洲视频免费在线 | www.久久免费视频 | 99精品国产成人一区二区 | 日韩av播放在线 | 色综合亚洲精品激情狠狠 | 超碰久热 | 中文字幕永久免费 | 日韩av图片 | 久久久久看片 | 中文字幕中文字幕 | 日韩免费在线观看视频 | 天天色宗合 | 亚洲精品国精品久久99热一 | 久久久久久久久久福利 | 国产99一区 | 青草草在线| 久久丝袜视频 | 91av在线播放视频 | 亚洲精品乱码久久久久久按摩 | 色综合天天做天天爱 | 亚洲一级国产 | 国产尤物在线视频 | 免费一级片在线观看 | 91成人精品在线 | 精品国产一区二区三区四区在线观看 | 在线播放视频一区 | 精品v亚洲v欧美v高清v | 国产成人一区二区三区久久精品 | 国产又黄又爽又猛视频日本 | 最近中文字幕国语免费高清6 | 色之综合网 | 国产成人一区二区三区久久精品 | 国内精品在线观看视频 | 国产婷婷精品av在线 | 色婷婷狠狠操 | 美女视频免费一区二区 | 国产亚洲欧美精品久久久久久 | 色偷偷88欧美精品久久久 | 色com网| 在线观看成人 | 色狠狠综合天天综合综合 | 日韩中文字幕视频在线 | 91精品国自产在线偷拍蜜桃 | 国产小视频免费在线网址 | 91精品国产99久久久久 | 涩av在线 | 日韩综合精品 | 久久久久久久久久影视 | 精品久久久久久综合日本 | 国产美女视频黄a视频免费 久久综合九色欧美综合狠狠 | 国产成本人视频在线观看 | 久热久草在线 | av中文字幕av | 丁香六月五月婷婷 | 狠狠狠色狠狠色综合 | 日韩电影久久久 | 成人av在线资源 | 日韩欧美一区二区三区黑寡妇 | av在线电影免费观看 | 久久国产精品免费观看 | 国产精品不卡在线 | 国产亚洲精品久久19p | 国产字幕在线看 | 婷婷日韩| 免费av网站观看 | 天天草综合 | 久久亚洲国产精品 | 午夜精品久久久久久久久久久久 | 成人av免费播放 | 97看片吧 | 久久久国产网站 | 久久综合五月天 | 日韩欧美高清在线观看 |