騰訊一面:內(nèi)存滿了,會發(fā)生什么?

      網(wǎng)友投稿 841 2025-04-03

      大家好,我是小林。


      前幾天有位讀者留言說,面騰訊時,被問了兩個內(nèi)存管理的問題:

      先來說說第一個問題:虛擬內(nèi)存有什么作用?

      第一,由于每個進程都有自己的頁表,所以每個進程的虛擬內(nèi)存空間就是相互獨立的。進程也沒有辦法訪問其他進程的頁表,所以這些頁表是私有的。這就解決了多進程之間地址沖突的問題。

      第二,頁表里的頁表項中除了物理地址之外,還有一些標(biāo)記屬性的比特,比如控制一個頁的讀寫權(quán)限,標(biāo)記該頁是否存在等。在內(nèi)存訪問方面,操作系統(tǒng)提供了更好的安全性。

      然后今天主要是聊聊第二個問題,「系統(tǒng)內(nèi)存緊張時,會發(fā)生什么?」

      發(fā)車!

      內(nèi)存分配的過程是怎樣的?

      應(yīng)用程序通過 malloc 函數(shù)申請內(nèi)存的時候,實際上申請的是虛擬內(nèi)存,此時并不會分配物理內(nèi)存。

      當(dāng)應(yīng)用程序讀寫了這塊虛擬內(nèi)存,CPU 就會去訪問這個虛擬內(nèi)存, 這時會發(fā)現(xiàn)這個虛擬內(nèi)存沒有映射到物理內(nèi)存, CPU 就會產(chǎn)生缺頁中斷,進程會從用戶態(tài)切換到內(nèi)核態(tài),并將缺頁中斷交給內(nèi)核的 Page Fault Handler (缺頁中斷函數(shù))處理。

      缺頁中斷處理函數(shù)會看是否有空閑的物理內(nèi)存,如果有,就直接分配物理內(nèi)存,并建立虛擬內(nèi)存與物理內(nèi)存之間的映射關(guān)系。

      如果沒有空閑的物理內(nèi)存,那么內(nèi)核就會開始進行回收內(nèi)存的工作,回收的方式主要是兩種:直接內(nèi)存回收和后臺內(nèi)存回收。

      后臺內(nèi)存回收(kswapd):在物理內(nèi)存緊張的時候,會喚醒 kswapd 內(nèi)核線程來回收內(nèi)存,這個回收內(nèi)存的過程異步的,不會阻塞進程的執(zhí)行。

      直接內(nèi)存回收(direct reclaim):如果后臺異步回收跟不上進程內(nèi)存申請的速度,就會開始直接回收,這個回收內(nèi)存的過程是同步的,會阻塞進程的執(zhí)行。

      如果直接內(nèi)存回收后,空閑的物理內(nèi)存仍然無法滿足此次物理內(nèi)存的申請,那么內(nèi)核就會放最后的大招了 ——觸發(fā) OOM (Out of Memory)機制。

      OOM Killer 機制會根據(jù)算法選擇一個占用物理內(nèi)存較高的進程,然后將其殺死,以便釋放內(nèi)存資源,如果物理內(nèi)存依然不足,OOM Killer 會繼續(xù)殺死占用物理內(nèi)存較高的進程,直到釋放足夠的內(nèi)存位置。

      申請物理內(nèi)存的過程如下圖:

      哪些內(nèi)存可以被回收?

      系統(tǒng)內(nèi)存緊張的時候,就會進行回收內(nèi)測的工作,那具體哪些內(nèi)存是可以被回收的呢?

      主要有兩類內(nèi)存可以被回收,而且它們的回收方式也不同。

      文件頁(File-backed Page):內(nèi)核緩存的磁盤數(shù)據(jù)(Buffer)和內(nèi)核緩存的文件數(shù)據(jù)(Cache)都叫作文件頁。大部分文件頁,都可以直接釋放內(nèi)存,以后有需要時,再從磁盤重新讀取就可以了。而那些被應(yīng)用程序修改過,并且暫時還沒寫入磁盤的數(shù)據(jù)(也就是臟頁),就得先寫入磁盤,然后才能進行內(nèi)存釋放。所以,回收干凈頁的方式是直接釋放內(nèi)存,回收臟頁的方式是先寫回磁盤后再釋放內(nèi)存。

      匿名頁(Anonymous Page):應(yīng)用程序通過 mmap 動態(tài)分配的堆內(nèi)存叫作匿名頁,這部分內(nèi)存很可能還要再次被訪問,所以不能直接釋放內(nèi)存,它們回收的方式是通過 Linux 的 Swap 機制,Swap 會把不常訪問的內(nèi)存先寫到磁盤中,然后釋放這些內(nèi)存,給其他更需要的進程使用。再次訪問這些內(nèi)存時,重新從磁盤讀入內(nèi)存就可以了。

      文件頁和匿名頁的回收都是基于 LRU 算法,也就是優(yōu)先回收不常訪問的內(nèi)存。LRU 回收算法,實際上維護著 active 和 inactive 兩個雙向鏈表,其中:

      active_list 活躍內(nèi)存頁鏈表,這里存放的是最近被訪問過(活躍)的內(nèi)存頁;

      inactive_list 不活躍內(nèi)存頁鏈表,這里存放的是很少被訪問(非活躍)的內(nèi)存頁;

      越接近鏈表尾部,就表示內(nèi)存頁越不常訪問。這樣,在回收內(nèi)存時,系統(tǒng)就可以根據(jù)活躍程度,優(yōu)先回收不活躍的內(nèi)存。

      活躍和非活躍的內(nèi)存頁,按照類型的不同,又分別分為文件頁和匿名頁。可以從 /proc/meminfo 中,查詢它們的大小,比如:

      # grep表示只保留包含active的指標(biāo)(忽略大小寫) # sort表示按照字母順序排序 [root@xiaolin ~]# cat /proc/meminfo | grep -i active | sort Active: 901456 kB Active(anon): 227252 kB Active(file): 674204 kB Inactive: 226232 kB Inactive(anon): 41948 kB Inactive(file): 184284 kB

      1

      2

      3

      4

      5

      6

      7

      8

      9

      回收內(nèi)存帶來的性能影響

      在前面我們知道了回收內(nèi)存有兩種方式。

      一種是后臺內(nèi)存回收,也就是喚醒 kswapd 內(nèi)核線程,這種方式是異步回收的,不會阻塞進程。

      一種是直接內(nèi)存回收,這種方式是同步回收的,會阻塞進程,這樣就會造成很長時間的延遲,以及系統(tǒng)的 CPU 利用率會升高,最終引起系統(tǒng)負(fù)荷飆高。

      可被回收的內(nèi)存類型有文件頁和匿名頁:

      文件頁的回收:對于干凈頁是直接釋放內(nèi)存,這個操作不會影響性能,而對于臟頁會先寫回到磁盤再釋放內(nèi)存,這個操作會發(fā)生磁盤 I/O 的,這個操作是會影響系統(tǒng)性能的。

      匿名頁的回收:如果開啟了 Swap 機制,那么 Swap 機制會將不常訪問的匿名頁換出到磁盤中,下次訪問時,再從磁盤換入到內(nèi)存中,這個操作是會影響系統(tǒng)性能的。

      可以看到,回收內(nèi)存的操作基本都會發(fā)生磁盤 I/O 的,如果回收內(nèi)存的操作很頻繁,意味著磁盤 I/O 次數(shù)會很多,這個過程勢必會影響系統(tǒng)的性能,整個系統(tǒng)給人的感覺就是很卡。

      下面針對回收內(nèi)存導(dǎo)致的性能影響,說說常見的解決方式。

      調(diào)整文件頁和匿名頁的回收傾向

      從文件頁和匿名頁的回收操作來看,文件頁的回收操作對系統(tǒng)的影響相比匿名頁的回收操作會少一點,因為文件頁對于干凈頁回收是不會發(fā)生磁盤 I/O 的,而匿名頁的 Swap 換入換出這兩個操作都會發(fā)生磁盤 I/O。

      Linux 提供了一個 /proc/sys/vm/swappiness 選項,用來調(diào)整文件頁和匿名頁的回收傾向。

      swappiness 的范圍是 0-100,數(shù)值越大,越積極使用 Swap,也就是更傾向于回收匿名頁;數(shù)值越小,越消極使用 Swap,也就是更傾向于回收文件頁。

      [root@xiaolin ~]# cat /proc/sys/vm/swappiness 0

      1

      2

      一般建議 swappiness 設(shè)置為 0(默認(rèn)就是 0),這樣在回收內(nèi)存的時候,會更傾向于文件頁的回收,但是并不代表不會回收匿名頁。

      盡早觸發(fā) kswapd 內(nèi)核線程異步回收內(nèi)存

      如何查看系統(tǒng)的直接內(nèi)存回收和后臺內(nèi)存回收的指標(biāo)?

      我們可以使用 sar -B 1 命令來觀察:

      圖中紅色框住的就是后臺內(nèi)存回收和直接內(nèi)存回收的指標(biāo),它們分別表示:

      pgscank/s : kswapd(后臺回收線程) 每秒掃描的 page 個數(shù)。

      pgscand/s: 應(yīng)用程序在內(nèi)存申請過程中每秒直接掃描的 page 個數(shù)。

      pgsteal/s: 掃描的 page 中每秒被回收的個數(shù)(pgscank+pgscand)。

      如果系統(tǒng)時不時發(fā)生抖動,并且在抖動的時間段里如果通過 sar -B 觀察到 pgscand 數(shù)值很大,那大概率是因為「直接內(nèi)存回收」導(dǎo)致的。

      針對這個問題,解決的辦法就是,可以通過盡早的觸發(fā)「后臺內(nèi)存回收」來避免應(yīng)用程序進行直接內(nèi)存回收。

      什么條件下才能觸發(fā) kswapd 內(nèi)核線程回收內(nèi)存呢?

      內(nèi)核定義了三個內(nèi)存閾值(watermark,也稱為水位),用來衡量當(dāng)前剩余內(nèi)存(pages_free)是否充裕或者緊張,分別是:

      頁最小閾值(pages_min);

      頁低閾值(pages_low);

      頁高閾值(pages_high);

      這三個內(nèi)存閾值會劃分為四種內(nèi)存使用情況,如下圖:

      kswapd 會定期掃描內(nèi)存的使用情況,根據(jù)剩余內(nèi)存(pages_free)的情況來進行內(nèi)存回收的工作。

      圖中綠色部分:如果剩余內(nèi)存(pages_free)大于 頁高閾值(pages_high),說明剩余內(nèi)存是充足的;

      圖中藍(lán)色部分:如果剩余內(nèi)存(pages_free)在頁高閾值(pages_high)和頁低閾值(pages_low)之間,說明內(nèi)存有一定壓力,但還可以滿足應(yīng)用程序申請內(nèi)存的請求;

      圖中橙色部分:如果剩余內(nèi)存(pages_free)在頁低閾值(pages_low)和頁最小閾值(pages_min)之間,說明內(nèi)存壓力比較大,剩余內(nèi)存不多了。這時 kswapd0 會執(zhí)行內(nèi)存回收,直到剩余內(nèi)存大于高閾值(pages_high)為止。雖然會觸發(fā)內(nèi)存回收,但是不會阻塞應(yīng)用程序,因為兩者關(guān)系是異步的。

      圖中紅色部分:如果剩余內(nèi)存(pages_free)小于頁最小閾值(pages_min),說明用戶可用內(nèi)存都耗盡了,此時就會觸發(fā)直接內(nèi)存回收,這時應(yīng)用程序就會被阻塞,因為兩者關(guān)系是同步的。

      可以看到,當(dāng)剩余內(nèi)存頁(pages_free)小于頁低閾值(pages_low),就會觸發(fā) kswapd 進行后臺回收,然后 kswapd 會一直回收到剩余內(nèi)存頁(pages_free)大于頁高閾值(pages_high)。

      也就是說 kswapd 的活動空間只有 pages_low 與 pages_min 之間的這段區(qū)域,如果剩余內(nèi)測低于了 pages_min 會觸發(fā)直接內(nèi)存回收,高于了 pages_high 又不會喚醒 kswapd。

      頁低閾值(pages_low)可以通過內(nèi)核選項 /proc/sys/vm/min_free_kbytes (該參數(shù)代表系統(tǒng)所保留空閑內(nèi)存的最低限)來間接設(shè)置。

      min_free_kbytes 雖然設(shè)置的是頁最小閾值(pages_min),但是頁高閾值(pages_high)和頁低閾值(pages_low)都是根據(jù)頁最小閾值(pages_min)計算生成的,它們之間的計算關(guān)系如下:

      pages_min = min_free_kbytes pages_low = pages_min*5/4 pages_high = pages_min*3/2

      1

      2

      3

      如果系統(tǒng)時不時發(fā)生抖動,并且通過 sar -B 觀察到 pgscand 數(shù)值很大,那大概率是因為直接內(nèi)存回收導(dǎo)致的,這時可以增大 min_free_kbytes 這個配置選項來及早地觸發(fā)后臺回收,然后繼續(xù)觀察 pgscand 是否會降為 0。

      增大了 min_free_kbytes 配置后,這會使得系統(tǒng)預(yù)留過多的空閑內(nèi)存,從而在一定程度上降低了應(yīng)用程序可使用的內(nèi)存量,這在一定程度上浪費了內(nèi)存。極端情況下設(shè)置 min_free_kbytes 接近實際物理內(nèi)存大小時,留給應(yīng)用程序的內(nèi)存就會太少而可能會頻繁地導(dǎo)致 OOM 的發(fā)生。

      所以在調(diào)整 min_free_kbytes 之前,需要先思考一下,應(yīng)用程序更加關(guān)注什么,如果關(guān)注延遲那就適當(dāng)?shù)卦龃?min_free_kbytes,如果關(guān)注內(nèi)存的使用量那就適當(dāng)?shù)卣{(diào)小 min_free_kbytes。

      NUMA 架構(gòu)下的內(nèi)存回收策略

      什么是 NUMA 架構(gòu)?

      再說 NUMA 架構(gòu)前,先給大家說說 SMP 架構(gòu),這兩個架構(gòu)都是針對 CPU 的。

      SMP 指的是一種多個 CPU 處理器共享資源的電腦硬件架構(gòu),也就是說每個 CPU 地位平等,它們共享相同的物理資源,包括總線、內(nèi)存、IO、操作系統(tǒng)等。每個 CPU 訪問內(nèi)存所用時間都是相同的,因此,這種系統(tǒng)也被稱為一致存儲訪問結(jié)構(gòu)(UMA,Uniform Memory Access)。

      隨著 CPU 處理器核數(shù)的增多,多個 CPU 都通過一個總線訪問內(nèi)存,這樣總線的帶寬壓力會越來越大,同時每個 CPU 可用帶寬會減少,這也就是 SMP 架構(gòu)的問題。

      為了解決 SMP 架構(gòu)的問題,就研制出了 NUMA 結(jié)構(gòu),即非一致存儲訪問結(jié)構(gòu)(Non-uniform memory access,NUMA)。

      NUMA 架構(gòu)將每個 CPU 進行了分組,每一組 CPU 用 Node 來表示,一個 Node 可能包含多個 CPU 。

      每個 Node 有自己獨立的資源,包括內(nèi)存、IO 等,每個 Node 之間可以通過互聯(lián)模塊總線(QPI)進行通信,所以,也就意味著每個 Node 上的 CPU 都可以訪問到整個系統(tǒng)中的所有內(nèi)存。但是,訪問遠(yuǎn)端 Node 的內(nèi)存比訪問本地內(nèi)存要耗時很多。

      NUMA 架構(gòu)跟回收內(nèi)存有什么關(guān)系?

      在 NUMA 架構(gòu)下,當(dāng)某個 Node 內(nèi)存不足時,系統(tǒng)可以從其他 Node 尋找空閑內(nèi)存,也可以從本地內(nèi)存中回收內(nèi)存。

      具體選哪種模式,可以通過 /proc/sys/vm/zone_reclaim_mode 來控制。它支持以下幾個選項:

      0 (默認(rèn)值):在回收本地內(nèi)存之前,在其他 Node 尋找空閑內(nèi)存;

      1:只回收本地內(nèi)存;

      2:只回收本地內(nèi)存,在本地回收內(nèi)存時,可以將文件頁中的臟頁寫回硬盤,以回收內(nèi)存。

      4:只回收本地內(nèi)存,在本地回收內(nèi)存時,可以用 swap 方式回收內(nèi)存。

      在使用 NUMA 架構(gòu)的服務(wù)器,如果系統(tǒng)出現(xiàn)還有一半內(nèi)存的時候,卻發(fā)現(xiàn)系統(tǒng)頻繁觸發(fā)「直接內(nèi)存回收」,導(dǎo)致了影響了系統(tǒng)性能,那么大概率是因為 zone_reclaim_mode 沒有設(shè)置為 0 ,導(dǎo)致當(dāng)本地內(nèi)存不足的時候,只選擇回收本地內(nèi)存的方式,而不去使用其他 Node 的空閑內(nèi)存。

      雖然說訪問遠(yuǎn)端 Node 的內(nèi)存比訪問本地內(nèi)存要耗時很多,但是相比內(nèi)存回收的危害而言,訪問遠(yuǎn)端 Node 的內(nèi)存帶來的性能影響還是比較小的。因此,zone_reclaim_mode 一般建議設(shè)置為 0。

      如何保護一個進程不被 OOM 殺掉呢?

      在系統(tǒng)空閑內(nèi)存不足的情況,進程申請了一個很大的內(nèi)存,如果直接內(nèi)存回收都無法回收出足夠大的空閑內(nèi)存,那么就會觸發(fā) OOM 機制,內(nèi)核就會根據(jù)算法選擇一個進程殺掉。

      Linux 到底是根據(jù)什么標(biāo)準(zhǔn)來選擇被殺的進程呢?這就要提到一個在 Linux 內(nèi)核里有一個 oom_badness() 函數(shù),它會把系統(tǒng)中可以被殺掉的進程掃描一遍,并對每個進程打分,得分最高的進程就會被首先殺掉。

      進程得分的結(jié)果受下面這兩個方面影響:

      第一,進程已經(jīng)使用的物理內(nèi)存頁面數(shù)。

      第二,每個進程的 OOM 校準(zhǔn)值 oom_score_adj。它是可以通過 /proc/[pid]/oom_score_adj 來配置的。我們可以在設(shè)置 -1000 到 1000 之間的任意一個數(shù)值,調(diào)整進程被 OOM Kill 的幾率。

      函數(shù) oom_badness() 里的最終計算方法是這樣的:

      // points 代表打分的結(jié)果 // process_pages 代表進程已經(jīng)使用的物理內(nèi)存頁面數(shù) // oom_score_adj 代表 OOM 校準(zhǔn)值 // totalpages 代表系統(tǒng)總的可用頁面數(shù) points = process_pages + oom_score_adj*totalpages/1000

      1

      2

      3

      4

      5

      用「系統(tǒng)總的可用頁面數(shù)」乘以 「OOM 校準(zhǔn)值 oom_score_adj」再除以 1000,最后再加上進程已經(jīng)使用的物理頁面數(shù),計算出來的值越大,那么這個進程被 OOM Kill 的幾率也就越大。

      每個進程的 oom_score_adj 默認(rèn)值都為 0,所以最終得分跟進程自身消耗的內(nèi)存有關(guān),消耗的內(nèi)存越大越容易被殺掉。我們可以通過調(diào)整 oom_score_adj 的數(shù)值,來改成進程的得分結(jié)果:

      如果你不想某個進程被首先殺掉,那你可以調(diào)整該進程的 oom_score_adj,從而改變這個進程的得分結(jié)果,降低該進程被 OOM 殺死的概率。

      如果你想某個進程無論如何都不能被殺掉,那你可以將 oom_score_adj 配置為 -1000。

      我們最好將一些很重要的系統(tǒng)服務(wù)的 oom_score_adj 配置為 -1000,比如 sshd,因為這些系統(tǒng)服務(wù)一旦被殺掉,我們就很難再登陸進系統(tǒng)了。

      但是,不建議將我們自己的業(yè)務(wù)程序的 oom_score_adj 設(shè)置為 -1000,因為業(yè)務(wù)程序一旦發(fā)生了內(nèi)存泄漏,而它又不能被殺掉,這就會導(dǎo)致隨著它的內(nèi)存開銷變大,OOM killer 不停地被喚醒,從而把其他進程一個個給殺掉。

      參考資料:

      https://time.geekbang.org/column/article/277358

      https://time.geekbang.org/column/article/75797

      騰訊一面:內(nèi)存滿了,會發(fā)生什么?

      https://www.jianshu.com/p/e40e8813842f

      總結(jié)

      內(nèi)核在給應(yīng)用程序分配物理內(nèi)存的時候,如果空閑物理內(nèi)存不夠,那么就會進行內(nèi)存回收的工作,主要有兩種方式:

      后臺內(nèi)存回收:在物理內(nèi)存緊張的時候,會喚醒 kswapd 內(nèi)核線程來回收內(nèi)存,這個回收內(nèi)存的過程異步的,不會阻塞進程的執(zhí)行。

      直接內(nèi)存回收:如果后臺異步回收跟不上進程內(nèi)存申請的速度,就會開始直接回收,這個回收內(nèi)存的過程是同步的,會阻塞進程的執(zhí)行。

      可被回收的內(nèi)存類型有文件頁和匿名頁:

      文件頁的回收:對于干凈頁是直接釋放內(nèi)存,這個操作不會影響性能,而對于臟頁會先寫回到磁盤再釋放內(nèi)存,這個操作會發(fā)生磁盤 I/O 的,這個操作是會影響系統(tǒng)性能的。

      匿名頁的回收:如果開啟了 Swap 機制,那么 Swap 機制會將不常訪問的匿名頁換出到磁盤中,下次訪問時,再從磁盤換入到內(nèi)存中,這個操作是會影響系統(tǒng)性能的。

      文件頁和匿名頁的回收都是基于 LRU 算法,也就是優(yōu)先回收不常訪問的內(nèi)存。回收內(nèi)存的操作基本都會發(fā)生磁盤 I/O 的,如果回收內(nèi)存的操作很頻繁,意味著磁盤 I/O 次數(shù)會很多,這個過程勢必會影響系統(tǒng)的性能。

      針對回收內(nèi)存導(dǎo)致的性能影響,常見的解決方式。

      設(shè)置 /proc/sys/vm/swappiness,調(diào)整文件頁和匿名頁的回收傾向,盡量傾向于回收文件頁;

      設(shè)置 /proc/sys/vm/min_free_kbytes,調(diào)整 kswapd 內(nèi)核線程異步回收內(nèi)存的時機;

      設(shè)置 /proc/sys/vm/zone_reclaim_mode,調(diào)整 NUMA 架構(gòu)下內(nèi)存回收策略,建議設(shè)置為 0,這樣在回收本地內(nèi)存之前,會在其他 Node 尋找空閑內(nèi)存,從而避免在系統(tǒng)還有很多空閑內(nèi)存的情況下,因本地 Node 的本地內(nèi)存不足,發(fā)生頻繁直接內(nèi)存回收導(dǎo)致性能下降的問題;

      在經(jīng)歷完直接內(nèi)存回收后,空閑的物理內(nèi)存大小依然不夠,那么就會觸發(fā) OOM 機制,OOM killer 就會根據(jù)每個進程的內(nèi)存占用情況和 oom_score_adj 的值進行打分,得分最高的進程就會被首先殺掉。

      我們可以通過調(diào)整進程的 /proc/[pid]/oom_score_adj 值,來降低被 OOM killer 殺掉的概率。

      完!

      任務(wù)調(diào)度 虛擬化

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:使用機器人操作系統(tǒng)ROS 2和仿真軟件Gazebo 9命令遙控可視化教程(二)
      下一篇:Excel添加計算公式的方法步驟詳解
      相關(guān)文章
      亚洲AV无码一区二区二三区入口| 亚洲不卡av不卡一区二区| 亚洲成熟xxxxx电影| 亚洲一区二区三区香蕉| 亚洲第一区在线观看| 日韩色视频一区二区三区亚洲 | 亚洲精品国产第1页| 亚洲制服中文字幕第一区| 久久精品国产亚洲av麻豆 | 亚洲中文字幕久久精品无码APP | 亚洲一级毛片在线播放| 亚洲免费观看网站| 亚洲婷婷综合色高清在线| 亚洲天堂福利视频| 久久狠狠爱亚洲综合影院 | 亚洲人成伊人成综合网久久久| 国产亚洲欧洲Aⅴ综合一区| 夜夜春亚洲嫩草影院| 亚洲午夜国产精品无码老牛影视| 亚洲欧洲精品无码AV| 久久综合日韩亚洲精品色| 亚洲成av人影院| 久久亚洲精精品中文字幕| 亚洲另类春色国产精品| 国产 亚洲 中文在线 字幕| 亚洲精品成a人在线观看夫| 日韩亚洲翔田千里在线| mm1313亚洲精品无码又大又粗| 亚洲精品国产精品国自产观看| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 亚洲国产成人五月综合网| 国产亚洲一区二区三区在线不卡| 中文字幕在亚洲第一在线| 国产亚洲综合成人91精品| 亚洲影院在线观看| 中文字幕亚洲男人的天堂网络| 亚洲看片无码在线视频| 亚洲av第一网站久章草| 亚洲国产精品专区在线观看| 亚洲精品无码mv在线观看网站 | 亚洲好看的理论片电影|