<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深度好文:Linux操作系統(tǒng)內(nèi)存

          共 7583字,需瀏覽 16分鐘

           ·

          2022-03-06 00:03




          Linux 內(nèi)存是后臺開發(fā)人員,需要深入了解的計算機資源。合理的使用內(nèi)存,有助于提升機器的性能和穩(wěn)定性。本文主要介紹Linux 內(nèi)存組織結(jié)構和頁面布局,內(nèi)存碎片產(chǎn)生原因和優(yōu)化算法,Linux 內(nèi)核幾種內(nèi)存管理的方法,內(nèi)存使用場景以及內(nèi)存使用的那些坑。


          從內(nèi)存的原理和結(jié)構,到內(nèi)存的算法優(yōu)化,再到使用場景,去探尋內(nèi)存管理的機制和奧秘。


          一、走進Linux 內(nèi)存

          1、內(nèi)存是什么?

          1)內(nèi)存又稱主存,是 CPU 能直接尋址的存儲空間,由半導體器件制成

          2)內(nèi)存的特點是存取速率快

          2、內(nèi)存的作用

          • 1)暫時存放 cpu 的運算數(shù)據(jù)

          • 2)硬盤等外部存儲器交換的數(shù)據(jù)

          • 3)保障 cpu 計算的穩(wěn)定性和高性能


          二、 Linux 內(nèi)存地址空間

          1、Linux 內(nèi)存地址空間 Linux 內(nèi)存管理全貌

          2、內(nèi)存地址——用戶態(tài)&內(nèi)核態(tài)

          • 用戶態(tài):Ring3 運行于用戶態(tài)的代碼則要受到處理器的諸多

          • 內(nèi)核態(tài):Ring0 在處理器的存儲保護中,核心態(tài)

          • 用戶態(tài)切換到內(nèi)核態(tài)的 3 種方式:系統(tǒng)調(diào)用、異常、外設中斷

          • 區(qū)別:每個進程都有完全屬于自己的,獨立的,不被干擾的內(nèi)存空間;用戶態(tài)的程序就不能隨意操作內(nèi)核地址空間,具有一定的安全保護作用;內(nèi)核態(tài)線程共享內(nèi)核地址空間;

          3、內(nèi)存地址——MMU 地址轉(zhuǎn)換

          • MMU 是一種硬件電路,它包含兩個部件,一個是分段部件,一個是分頁部件

          • 分段機制把一個邏輯地址轉(zhuǎn)換為線性地址

          • 分頁機制把一個線性地址轉(zhuǎn)換為物理地址

          4、內(nèi)存地址——分段機制

          1)?段選擇符

          • 為了方便快速檢索段選擇符,處理器提供了 6 個分段寄存器來緩存段選擇符,它們是:cs,ss,ds,es,fs 和 gs

          • 段的基地址(Base Address):在線性地址空間中段的起始地址

          • 段的界限(Limit):在虛擬地址空間中,段內(nèi)可以使用的最大偏移量

          2)?分段實現(xiàn)

          • 邏輯地址的段寄存器中的值提供段描述符,然后從段描述符中得到段基址和段界限,然后加上邏輯地址的偏移量,就得到了線性地址

          5、內(nèi)存地址——分頁機制(32 位)


          • 分頁機制是在分段機制之后進行的,它進一步將線性地址轉(zhuǎn)換為物理地址

          • 10 位頁目錄,10 位頁表項,?12 位頁偏移地址

          • 單頁的大小為 4KB

          6、用戶態(tài)地址空間

          • TEXT:代碼段可執(zhí)行代碼、字符串字面值、只讀變量

          • DATA:數(shù)據(jù)段,映射程序中已經(jīng)初始化的全局變量

          • BSS 段:存放程序中未初始化的全局變量

          • HEAP:運行時的堆,在程序運行中使用 malloc 申請的內(nèi)存區(qū)域

          • MMAP:共享庫及匿名文件的映射區(qū)域

          • STACK:用戶進程棧

          7、內(nèi)核態(tài)地址空間

          • 直接映射區(qū):線性空間中從 3G 開始最大 896M 的區(qū)間,為直接內(nèi)存映射區(qū)

          • 動態(tài)內(nèi)存映射區(qū):該區(qū)域由內(nèi)核函數(shù) vmalloc 來分配

          • 永久內(nèi)存映射區(qū):該區(qū)域可訪問高端內(nèi)存

          • 固定映射區(qū):該區(qū)域和 4G 的頂端只有 4k 的隔離帶,其每個地址項都服務于特定的用途,如:ACPI_BASE 等

          8、進程內(nèi)存空間

          • 用戶進程通常情況只能訪問用戶空間的虛擬地址,不能訪問內(nèi)核空間虛擬地址

          • 內(nèi)核空間是由內(nèi)核負責映射,不會跟著進程變化;內(nèi)核空間地址有自己對應的頁表,用戶進程各自有不同額頁表

          三、 Linux 內(nèi)存分配算法

          內(nèi)存管理算法:對討厭自己管理內(nèi)存的人來說是天賜的禮物。

          1、內(nèi)存碎片

          1)??? 基本原理

          • 產(chǎn)生原因:內(nèi)存分配較小,并且分配的這些小的內(nèi)存生存周期又較長,反復申請后將產(chǎn)生內(nèi)存碎片的出現(xiàn)

          • 優(yōu)點:提高分配速度,便于內(nèi)存管理,防止內(nèi)存泄露

          • 缺點:大量的內(nèi)存碎片會使系統(tǒng)緩慢,內(nèi)存使用率低,浪費大

          2)?如何避免內(nèi)存碎片

          • 少用動態(tài)內(nèi)存分配的函數(shù)(盡量使用棧空間)

          • 分配內(nèi)存和釋放的內(nèi)存盡量在同一個函數(shù)中

          • 盡量一次性申請較大的內(nèi)存,而不要反復申請小內(nèi)存

          • 盡可能申請大塊的 2 的指數(shù)冪大小的內(nèi)存空間

          • 外部碎片避免——伙伴系統(tǒng)算法

          • 內(nèi)部碎片避免——slab 算法

          • 自己進行內(nèi)存管理工作,設計內(nèi)存池

          2、伙伴系統(tǒng)算法——組織結(jié)構

          1)??? 概念

          • 為內(nèi)核提供了一種用于分配一組連續(xù)的頁而建立的一種高效的分配策略,并有效的解決了外碎片問題

          • 分配的內(nèi)存區(qū)是以頁框為基本單位的

          2)??? 外部碎片

          • 外部碎片指的是還沒有被分配出去(不屬于任何進程),但由于太小了無法分配給申請內(nèi)存空間的新進程的內(nèi)存空閑區(qū)域3)??? 組織結(jié)構

          • 把所有的空閑頁分組為 11 個塊鏈表,每個塊鏈表分別包含大小為 1,2,4,8,16,32,64,128,256,512 和 1024 個連續(xù)頁框的頁塊。最大可以申請 1024 個連續(xù)頁,對應 4MB 大小的連續(xù)內(nèi)存。

          3、伙伴系統(tǒng)算法——申請和回收

          1)??? 申請算法

          • 申請 2^i 個頁塊存儲空間,如果 2^i 對應的塊鏈表有空閑頁塊,則分配給應用

          • 如果沒有空閑頁塊,則查找 2^(i 1) 對應的塊鏈表是否有空閑頁塊,如果有,則分配 2^i 塊鏈表節(jié)點給應用,另外 2^i 塊鏈表節(jié)點插入到 2^i 對應的塊鏈表中

          • 如果 2^(i 1) 塊鏈表中沒有空閑頁塊,則重復步驟 2,直到找到有空閑頁塊的塊鏈表

          • 如果仍然沒有,則返回內(nèi)存分配失敗

          2)??? 回收算法

          • 釋放 2^i 個頁塊存儲空間,查找 2^i 個頁塊對應的塊鏈表,是否有與其物理地址是連續(xù)的頁塊,如果沒有,則無需合并

          • 如果有,則合并成 2^(i 1)的頁塊,以此類推,繼續(xù)查找下一級塊鏈接,直到不能合并為止

          3)??? 條件

          • 兩個塊具有相同的大小

          • 它們的物理地址是連續(xù)的

          • 頁塊大小相同

          4、如何分配 4M 以上內(nèi)存?

          1)??? 為何限制大塊內(nèi)存分配

          • 分配的內(nèi)存越大, 失敗的可能性越大

          • 大塊內(nèi)存使用場景少

          2)??? 內(nèi)核中獲取 4M 以上大內(nèi)存的方法

          • 修改 MAX_ORDER, 重新編譯內(nèi)核

          • 內(nèi)核啟動選型傳遞'mem='參數(shù), 如'mem=80M,預留部分內(nèi)存;然后通過

          • request_mem_region 和 ioremap_nocache 將預留的內(nèi)存映射到模塊中。需要修改內(nèi)核啟動參數(shù), 無需重新編譯內(nèi)核. 但這種方法不支持 x86 架構, 只支持 ARM, PowerPC 等非 x86 架構

          • 在 start_kernel 中 mem_init 函數(shù)之前調(diào)用 alloc_boot_mem 函數(shù)預分配大塊內(nèi)存, 需要重新編譯內(nèi)核

          • vmalloc 函數(shù),內(nèi)核代碼使用它來分配在虛擬內(nèi)存中連續(xù)但在物理內(nèi)存中不一定連續(xù)的內(nèi)存

          5、伙伴系統(tǒng)——反碎片機制

          1)??? 不可移動頁

          • 這些頁在內(nèi)存中有固定的位置,不能夠移動,也不可回收

          • 內(nèi)核代碼段,數(shù)據(jù)段,內(nèi)核 kmalloc() 出來的內(nèi)存,內(nèi)核線程占用的內(nèi)存等

          2)??? 可回收頁

          • 這些頁不能移動,但可以刪除。內(nèi)核在回收頁占據(jù)了太多的內(nèi)存時或者內(nèi)存短缺時進行頁面回收3)??? 可移動頁

          • 這些頁可以任意移動,用戶空間應用程序使用的頁都屬于該類別。它們是通過頁表映射的

          • 當它們移動到新的位置,頁表項也會相應的更新

          6、slab 算法——基本原理

          1)??? 基本概念

          • Linux 所使用的 slab 分配器的基礎是 Jeff Bonwick 為 SunOS 操作系統(tǒng)首次引入的一種算法

          • 它的基本思想是將內(nèi)核中經(jīng)常使用的對象放到高速緩存中,并且由系統(tǒng)保持為初始的可利用狀態(tài)。比如進程描述符,內(nèi)核中會頻繁對此數(shù)據(jù)進行申請和釋放

          2)??? 內(nèi)部碎片

          • 已經(jīng)被分配出去的的內(nèi)存空間大于請求所需的內(nèi)存空間3)??? 基本目標

          • 減少伙伴算法在分配小塊連續(xù)內(nèi)存時所產(chǎn)生的內(nèi)部碎片

          • 將頻繁使用的對象緩存起來,減少分配、初始化和釋放對象的時間開銷

          • 通過著色技術調(diào)整對象以更好的使用硬件高速緩存

          7、slab 分配器的結(jié)構

          • 由于對象是從 slab 中分配和釋放的,因此單個 slab 可以在 slab 列表之間進行移動

          • slabs_empty 列表中的 slab 是進行回收(reaping)的主要備選對象

          • slab 還支持通用對象的初始化,從而避免了為同一目而對一個對象重復進行初始化

          8、slab 高速緩存

          1)??? 普通高速緩存

          • slab 分配器所提供的小塊連續(xù)內(nèi)存的分配是通過通用高速緩存實現(xiàn)的

          • 通用高速緩存所提供的對象具有幾何分布的大小,范圍為 32 到 131072 字節(jié)。

          • 內(nèi)核中提供了 kmalloc() 和 kfree() 兩個接口分別進行內(nèi)存的申請和釋放

          2)??? 專用高速緩存

          • 內(nèi)核為專用高速緩存的申請和釋放提供了一套完整的接口,根據(jù)所傳入的參數(shù)為具體的對象分配 slab 緩存

          • kmem_cache_create() 用于對一個指定的對象創(chuàng)建高速緩存。它從 cache_cache 普通高速緩存中為新的專有緩存分配一個高速緩存描述符,并把這個描述符插入到高速緩存描述符形成的 cache_chain 鏈表中

          • kmem_cache_alloc() 在其參數(shù)所指定的高速緩存中分配一個 slab。相反, kmem_cache_free() 在其參數(shù)所指定的高速緩存中釋放一個 slab

          9、內(nèi)核態(tài)內(nèi)存池

          1)??? 基本原理

          • 先申請分配一定數(shù)量的、大小相等(一般情況下) 的內(nèi)存塊留作備用

          • 當有新的內(nèi)存需求時,就從內(nèi)存池中分出一部分內(nèi)存塊,若內(nèi)存塊不夠再繼續(xù)申請新的內(nèi)存

          • 這樣做的一個顯著優(yōu)點是盡量避免了內(nèi)存碎片,使得內(nèi)存分配效率得到提升

          2)??? 內(nèi)核 API

          • mempool_create 創(chuàng)建內(nèi)存池對象

          • mempool_alloc 分配函數(shù)獲得該對象

          • mempool_free 釋放一個對象

          • mempool_destroy 銷毀內(nèi)存池

          10、用戶態(tài)內(nèi)存池

          1)??? C++ 實例

          11、DMA 內(nèi)存

          1)??? 什么是 DMA

          • 直接內(nèi)存訪問是一種硬件機制,它允許外圍設備和主內(nèi)存之間直接傳輸它們的 I/O 數(shù)據(jù),而不需要系統(tǒng)處理器的參與2)??? DMA 控制器的功能

          • 能向 CPU 發(fā)出系統(tǒng)保持(HOLD)信號,提出總線接管請求

          • 當 CPU 發(fā)出允許接管信號后,負責對總線的控制,進入 DMA 方式

          • 能對存儲器尋址及能修改地址指針,實現(xiàn)對內(nèi)存的讀寫操作

          • 能決定本次 DMA 傳送的字節(jié)數(shù),判斷 DMA 傳送是否結(jié)束

          • 發(fā)出 DMA 結(jié)束信號,使 CPU 恢復正常工作狀態(tài)

          2)??? DMA 信號

          • DREQ:DMA 請求信號。是外設向 DMA 控制器提出要求,DMA 操作的申請信號

          • DACK:DMA 響應信號。是 DMA 控制器向提出 DMA 請求的外設表示已收到請求和正進行處理的信號

          • HRQ:DMA 控制器向 CPU 發(fā)出的信號,要求接管總線的請求信號。

          • HLDA:CPU 向 DMA 控制器發(fā)出的信號,允許接管總線的應答信號:

          四、 內(nèi)存使用場景

          out of memory 的時代過去了嗎?no,內(nèi)存再充足也不可任性使用。

          1、內(nèi)存的使用場景

          • page 管理

          • slab(kmalloc、內(nèi)存池)

          • 用戶態(tài)內(nèi)存使用(malloc、relloc 文件映射、共享內(nèi)存)

          • 程序的內(nèi)存 map(棧、堆、code、data)

          • 內(nèi)核和用戶態(tài)的數(shù)據(jù)傳遞(copy_from_user、copy_to_user)

          • 內(nèi)存映射(硬件寄存器、保留內(nèi)存)

          • DMA 內(nèi)存

          2、用戶態(tài)內(nèi)存分配函數(shù)

          • alloca 是向棧申請內(nèi)存,因此無需釋放

          • malloc 所分配的內(nèi)存空間未被初始化,使用 malloc() 函數(shù)的程序開始時(內(nèi)存空間還沒有被重新分配) 能正常運行,但經(jīng)過一段時間后(內(nèi)存空間已被重新分配) 可能會出現(xiàn)問題

          • calloc 會將所分配的內(nèi)存空間中的每一位都初始化為零

          • realloc 擴展現(xiàn)有內(nèi)存空間大小

          • a)如果當前連續(xù)內(nèi)存塊足夠 realloc 的話,只是將 p 所指向的空間擴大,并返回 p 的指針地址。這個時候 q 和 p 指向的地址是一樣的

          • b)如果當前連續(xù)內(nèi)存塊不夠長度,再找一個足夠長的地方,分配一塊新的內(nèi)存,q,并將 p 指向的內(nèi)容 copy 到 q,返回 q。并將 p 所指向的內(nèi)存空間刪除

          3、內(nèi)核態(tài)內(nèi)存分配函數(shù)


          函數(shù)分配原理最大內(nèi)存其他_get_free_pages直接對頁框進行操作4MB適用于分配較大量的連續(xù)物理內(nèi)存kmem_cache_alloc基于 slab 機制實現(xiàn)128KB適合需要頻繁申請釋放相同大小內(nèi)存塊時使用kmalloc基于 kmem_cache_alloc 實現(xiàn)128KB最常見的分配方式,需要小于頁框大小的內(nèi)存時可以使用vmalloc建立非連續(xù)物理內(nèi)存到虛擬地址的映射物理不連續(xù),適合需要大內(nèi)存,但是對地址連續(xù)性沒有要求的場合dma_alloc_coherent基于_alloc_pages 實現(xiàn)4MB適用于 DMA 操作ioremap實現(xiàn)已知物理地址到虛擬地址的映射適用于物理地址已知的場合,如設備驅(qū)動alloc_bootmem在啟動 kernel 時,預留一段內(nèi)存,內(nèi)核看不見小于物理內(nèi)存大小,內(nèi)存管理要求較高


          4、malloc 申請內(nèi)存


          • 調(diào)用 malloc 函數(shù)時,它沿 free_chuck_list 連接表尋找一個大到足以滿足用戶請求所需要的內(nèi)存塊

          • free_chuck_list 連接表的主要工作是維護一個空閑的堆空間緩沖區(qū)鏈表

          • 如果空間緩沖區(qū)鏈表沒有找到對應的節(jié)點,需要通過系統(tǒng)調(diào)用 sys_brk 延伸進程的棧空間

          5、缺頁異常

          • 通過 get_free_pages 申請一個或多個物理頁面

          • 換算 addr 在進程 pdg 映射中所在的 pte 地址

          • 將 addr 對應的 pte 設置為物理頁面的首地址

          • 系統(tǒng)調(diào)用:Brk—申請內(nèi)存小于等于 128kb,do_map—申請內(nèi)存大于 128kb

          6、用戶進程訪問內(nèi)存分析

          • 用戶態(tài)進程獨占虛擬地址空間,兩個進程的虛擬地址可相同

          • 在訪問用戶態(tài)虛擬地址空間時,如果沒有映射物理地址,通過系統(tǒng)調(diào)用發(fā)出缺頁異常

          • 缺頁異常陷入內(nèi)核,分配物理地址空間,與用戶態(tài)虛擬地址建立映射

          7、共享內(nèi)存

          1)??? 原理

          • 它允許多個不相關的進程去訪問同一部分邏輯內(nèi)存

          • 兩個運行中的進程之間傳輸數(shù)據(jù),共享內(nèi)存將是一種效率極高的解決方案

          • 兩個運行中的進程共享數(shù)據(jù),是進程間通信的高效方法,可有效減少數(shù)據(jù)拷貝的次數(shù)

          2)??? Shm 接口

          • shmget 創(chuàng)建共享內(nèi)存

          • shmat 啟動對該共享內(nèi)存的訪問,并把共享內(nèi)存連接到當前進程的地址空間

          • shmdt 將共享內(nèi)存從當前進程中分離

          五、 內(nèi)存使用那些坑

          1、C 內(nèi)存泄露

          • 在類的構造函數(shù)和析構函數(shù)中沒有匹配地調(diào)用 new 和 delete 函數(shù)

          • 沒有正確地清除嵌套的對象指針

          • 沒有將基類的析構函數(shù)定義為虛函數(shù)

          • 當基類的指針指向子類對象時,如果基類的析構函數(shù)不是 virtual,那么子類的析構函數(shù)將不會被調(diào)用,子類的資源沒有得到正確釋放,因此造成內(nèi)存泄露

          • 缺少拷貝構造函數(shù),按值傳遞會調(diào)用(拷貝)構造函數(shù),引用傳遞不會調(diào)用

          • 指向?qū)ο蟮闹羔様?shù)組不等同于對象數(shù)組,數(shù)組中存放的是指向?qū)ο蟮闹羔槪粌H要釋放每個對象的空間,還要釋放每個指針的空間

          • 缺少重載賦值運算符,也是逐個成員拷貝的方式復制對象,如果這個類的大小是可變的,那么結(jié)果就是造成內(nèi)存泄露

          2、C 野指針

          • 指針變量沒有初始化

          • 指針被 free 或 delete 后,沒有設置為 NULL

          • 指針操作超越了變量的作用范圍,比如返回指向棧內(nèi)存的指針就是野指針

          • 訪問空指針(需要做空判斷)

          • sizeof 無法獲取數(shù)組的大小

          • 試圖修改常量,如:char p='1234';p='1';

          3、C 資源訪問沖突

          • 多線程共享變量沒有用 valotile 修飾

          • 多線程訪問全局變量未加鎖

          • 全局變量僅對單進程有效

          • 多進程寫共享內(nèi)存數(shù)據(jù),未做同步處理

          • mmap 內(nèi)存映射,多進程不安全

          4、STL 迭代器失效

          • 被刪除的迭代器失效

          • 添加元素(insert/push_back 等)、刪除元素導致順序容器迭代器失效

          錯誤示例:刪除當前迭代器,迭代器會失效?

          正確示例:迭代器 erase 時,需保存下一個迭代器

          5、C++ 11 智能指針

          • auto_ptr 替換為 unique_ptr

          • 使用 make_shared 初始化一個 shared_ptr

          • weak_ptr 智能指針助手(1)原理分析:

            (2)數(shù)據(jù)結(jié)構:

            (3)使用方法:a. ?lock() 獲取所管理的對象的強引用指針 b. expired() 檢測所管理的對象是否已經(jīng)釋放 c. get() 訪問智能指針對象


          6、C++ 11 更小更快更安全

          • std::atomic 原子數(shù)據(jù)類型 多線程安全

          • std::array 定長數(shù)組開銷比 array 小和 std::vector 不同的是 array 的長度是固定的,不能動態(tài)拓展

          • std::vector vector 瘦身 shrink_to_fit():將 capacity 減少為于 size() 相同的大小

          • td::forward_list

          forward_list 是單鏈表(std::list 是雙鏈表),只需要順序遍歷的場合,forward_list 能更加節(jié)省內(nèi)存,插入和刪除的性能高于 list

          • std::unordered_map、std::unordered_set用 hash 實現(xiàn)的無序的容器,插入、刪除和查找的時間復雜度都是 O(1),在不關注容器內(nèi)元素順序的場合,使用 unordered 的容器能獲得更高的性能六、 如何查看內(nèi)存

          • 系統(tǒng)中內(nèi)存使用情況:/proc/meminfo ?

          • 進程的內(nèi)存使用情況:/proc/28040/status

          • 查詢內(nèi)存總使用率:free

          • 查詢進程 cpu 和內(nèi)存使用占比:top

          • 虛擬內(nèi)存統(tǒng)計:vmstat

          • 進程消耗內(nèi)存占比和排序:ps aux –sort -rss

          • 釋放系統(tǒng)內(nèi)存緩存:

            /proc/sys/vm/drop_caches

          • To free pagecache, use echo 1 > /proc/sys/vm/drop_caches

          • To free dentries and inodes, use echo 2 > /proc/sys/vm/drop_caches

          • To free pagecache, dentries and inodes, use echo 3 >/proc/sys/vm/drop_caches



          推薦閱讀:

          世界的真實格局分析,地球人類社會底層運行原理

          不是你需要中臺,而是一名合格的架構師(附各大廠中臺建設PPT)

          企業(yè)IT技術架構規(guī)劃方案

          論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

          華為干部與人才發(fā)展手冊(附PPT)

          企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

          【中臺實踐】華為大數(shù)據(jù)中臺架構分享.pdf

          華為的數(shù)字化轉(zhuǎn)型方法論

          華為如何實施數(shù)字化轉(zhuǎn)型(附PPT)

          超詳細280頁Docker實戰(zhàn)文檔!開放下載

          華為大數(shù)據(jù)解決方案(PPT)

          瀏覽 49
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  吖v在线视频免费观看免费观看 | 久草免费极品盛宴 | 天堂俺去俺来也www色官网 | 大骚逼视频 | 国产成人激情视频 |