精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

結合實例深入理解C++對象的內存布局

開發
本篇文章試著從實際的例子出發,幫助大家對 C++ 類成員變量和函數在內存布局有個直觀的理解

作者 | daemonzhao

通過實例來深入理解 C++ 對象的內存布局,包括基礎數據類、帶方法的類、私有成員、靜態成員、類繼承等。通過 GDB 查看對象的內存布局,探討成員變量、成員方法、虛函數表等在內存中的存儲位置和實現細節,幫助大家對 C++ 類成員變量和函數在內存布局有個直觀的理解。

因為二進制使用了不同版本的 proto 對象,對象的內存布局不一致導致讀、寫成員的內存地址錯亂,進而導致進程 crash 掉。這之中會出現下面的問題:

  • 對象在內存中是怎么布局的?
  • 成員方法是如何拿到成員變量的地址?

這些其實涉及 C++ 的對象模型,《深度探索 C++對象模型:Inside the C++ Object Model》這本書全面聊了這個問題,非常值得一讀。不過這本書讀起來并不容易,有的內容讀過后如果沒有加以實踐,也很難完全理解。本篇文章試著從實際的例子出發,幫助大家對 C++ 類成員變量和函數在內存布局有個直觀的理解,后面再讀這本書也會容易理解些。

簡單對象內存分布

首先以一個最簡單的 Basic 類為例,來看看只含有基本數據類型的對象是怎么分配內存的。

#include <iostream>
using namespace std;

class Basic {
public:
    int a;
    double b;
};

int main() {
    Basic temp;
    temp.a = 10;
    return 0;
}

編譯運行后,可以用 GDB 來查看對象的內存分布。如下圖:

對象 temp 的起始地址是 0x7fffffffe3b0,這是整個對象在內存中的位置。成員變量 a 的地址也是 0x7fffffffe3b0,表明 int a 是對象 temp 中的第一個成員,位于對象的起始位置。成員變量 b 的類型為 double,其地址是 0x7fffffffe3b8(a 的地址+8),內存布局如下圖:

這里 int 類型在當前平臺上占用 4 個字節(可以用 sizeof(int)驗證),而這里 double 成員的起始地址與 int 成員的起始地址之間相差 8 個字節,說明在 a 之后存在內存對齊填充(具體取決于編譯器的實現細節和平臺的對齊要求)。內存對齊要求數據的起始地址在某個特定大小(比如 4、8)的倍數上,這樣可以優化硬件和操作系統訪問內存的效率。這是因為許多處理器訪問對齊的內存地址比訪問非對齊地址更快。

另外在不進行內存對齊的情況下,較大的數據結構可能會跨越多個緩存行或內存頁邊界,這會導致額外的緩存行或頁的加載,降低內存訪問效率。不過大多時候我們不需要手動管理內存對齊,編譯器和操作系統會自動處理這些問題。

帶方法的對象內存分布

帶有方法的類又是什么樣呢?接著上面的例子,在類中增加一個方法 setB,用來設置其中成員 b 的值。

#include <iostream>

class Basic {
public:
    int a;
    double b;

    void setB(double value) {
        b = value; // 直接訪問成員變量b
    }
};

int main() {
    Basic temp;
    temp.a = 10;
    temp.setB(3.14);
    return 0;
}

用 GDB 打印 temp 對象以及成員變量的地址,發現內存布局和前面不帶方法的完全一樣。整個對象 size 依然是 16,a 和 b 的內存地址分布也是一致的。那么新增加的成員方法存儲在什么位置?成員方法中又是如何拿到成員變量的地址呢?

1.成員方法內存布局

可以在 GDB 里面打印下成員方法的地址,如下圖所示。

回憶下 Linux 中進程的內存布局,其中文本段(也叫代碼段)是存儲程序執行代碼的內存區域,通常是只讀的,以防止程序在運行時意外或惡意修改其執行代碼。這里 setB 方法地址 0x5555555551d2 就是位于程序的文本段內,可以在 GDB 中用 info target 驗證一下:

其中 .text 段的地址范圍是 0x0000555555555060 - 0x0000555555555251,setB 剛好在這個范圍內。至此前面第一個問題有了答案,成員方法存儲在進程的文本段,添加成員方法不會改變類實例對象的內存布局大小,它們也不占用對象實例的內存空間。

2.成員變量尋址

那么成員方法中又是如何拿到成員變量的地址呢?在解決這個疑問前,先來仔細看下 setB 的函數原型(void (*)(Basic * const, double)),這里函數的第一個參數是Basic* 指針,而在代碼中的調用是這樣:temp.setB(3.14)。這種用法其實是一種語法糖,編譯器在調用成員函數時自動將當前對象的地址作為 this 指針傳遞給了函數的。

(gdb) p &Basic::setB(double)
$7 = (void (*)(Basic * const, double)) 0x5555555551d2 <Basic::setB(double)>

這里參數傳遞了對象的地址,但是在函數里面是怎么拿到成員變量 b 的地址呢?我們在調用 setB 的地方打斷點,執行到斷點后,用 step 進入到函數,然后查看相應寄存器的值和匯編代碼。整個過程如下圖:

這里的匯編代碼展示了如何通過 this 指針和偏移量訪問 b。可以分為兩部分,第一部分是處理 this 指針和參數,第二部分是找到成員 b 的內存位置然后進行賦值。

  • 參數傳遞部分。這里mov %rdi,-0x8(%rbp)將 this 指針(通過 rdi 寄存器傳入)保存到棧上。將 double 類型的參數 value 通過 xmm0 寄存器傳入保存到棧上。這是 x86_64 機器下 GCC 編譯器的傳參規定,我們可以通過打印 $rdi 保存的地址來驗證確實是 temp 對象的開始地址。
  • 對象賦值部分。mov -0x8(%rbp),%rax 將 this 指針從棧上加載到 rax 寄存器中。類似的,movsd -0x10(%rbp),%xmm0 將參數 value 從棧上重新加載到 xmm0 寄存器中。movsd %xmm0,0x8(%rax) 將 value 寫入到 this 對象的 b 成員。這里 0x8(%rax) 表示 rax(即 this 指針)加上 8 字節的偏移,這個偏移正是成員變量 b 在 Basic 對象中的位置。

這個偏移是什么時候,怎么算出來的呢?其實成員變量的地址相對于對象地址是固定的,對象的地址加上成員變量在對象內的偏移量就是成員變量的實際地址。編譯器在編譯時,基于類定義中成員變量的聲明順序和編譯器的內存布局規則,計算每個成員變量相對于對象起始地址的偏移量。然后在運行時,通過基地址(即對象的地址)加上偏移量,就能夠計算出每個成員變量的準確地址。這個過程對于程序員來說是透明的,由編譯器和運行時系統自動處理。

3.函數調用約定與優化

上面的匯編代碼中,setB 的兩個參數,都是從寄存器先放到棧上,接著又從棧上放到寄存器進行操作,為什么要移來移去多此一舉呢?要回答這個問題,需要先了解函數的調用約定和寄存器使用。在 x86_64 架構的系統調用約定中,前幾個整數或指針參數通常通過寄存器(如 rdi, rsi, rdx, 等)傳遞,而浮點參數通過 xmm0 到 xmm7 寄存器傳遞。這種約定目的是為了提高函數調用的效率,因為使用寄存器傳遞參數比使用棧更快。

而將寄存器上的參數又移動到棧上,是為了保證寄存器中的值不被覆蓋。因為寄存器是有限的資源,在函數中可能會被多次用于不同的目的。將值保存到棧上可以讓函數內部自由地使用寄存器,而不必擔心覆蓋調用者的數據。

接著又將-0x8(%rbp) 放到 rax 寄存器,然后再通過movsd %xmm0,0x8(%rax)寫入成員變量 b 的值,為啥不直接從xmm0寄存器寫到基于 rbp 的偏移地址呢?這是因為 x86_64 的指令集和其操作模式通常支持使用寄存器間接尋址方式訪問數據。使用rax等通用寄存器作為中間步驟,是一種更通用和兼容的方法。

當然上面編譯過程沒有開啟編譯優化,所以編譯器采用了直接但效率不高的代碼生成策略,包括將參數和局部變量頻繁地在棧與寄存器間移動。而編譯器的優化策略可能會影響參數的處理方式。如果我們開啟編譯優化,如下:

$ g++ basic_method.cpp -o basic_method_O2 -O2 -g -std=c++11

生成的 main 函數匯編部分如下:

(gdb) disassemble /m main
=> 0x0000555555555060 <+0>: xor    %eax,%eax
   0x0000555555555062 <+2>: ret
   0x0000555555555063: data16 nopw %cs:0x0(%rax,%rax,1)
   0x000055555555506e: xchg   %ax,%ax

在 O2 優化級別下,編譯器認定 main 函數中的所有操作(包括創建 Basic 對象和對其成員變量的賦值操作)對程序的最終結果沒有影響,因此它們都被優化掉了。這是編譯器的“死代碼消除”,直接移除那些不影響程序輸出的代碼部分。

特殊成員內存分布

上面的成員都是 public 的,如果是 private(私有) 變量,私有方法呢?另外,靜態成員變量或者靜態成員方法,在內存中又是怎么布局呢?

1.私有成員

先來看私有成員,接著上面的例子,增加私有成員變量和方法。整體代碼如下:

#include <iostream>

class Basic {
public:
    int a;
    double b;

    void setB(double value) {
        b = value; // 直接訪問成員變量b
        secret(b);
    }
private:
    int c;
    double d;

    void secret(int temp) {
        d = temp + c;
    }
};

int main() {
    Basic temp;
    temp.a = 10;
    temp.setB(3.14);
    return 0;
}

編譯之后,通過 GDB,可以打印出所有成員變量的地址,發現這里私有變量的內存布局并沒有什么特殊地方,也是依次順序存儲在對象中。私有的方法也沒有特殊地方,一樣存儲在文本段。整體布局如下如:

那么 private 怎么進行可見性控制的呢?首先編譯期肯定是有保護的,這個很容易驗證,我們無法直接訪問 temp.c ,或者調用 secret 方法,因為直接會編譯出錯。

那么運行期是否有保護呢?我們來驗證下。前面已經驗證 private 成員變量也是根據偏移來找到內存位置的,我們可以在代碼中直接根據偏移找到內存位置并更改里面的值。

int* pC = reinterpret_cast<int*>(reinterpret_cast<char*>(&temp) + 16);
*pC = 12; // 直接修改c的值

這里修改后,可以增加一個 show 方法打印所有成員的值,發現這里 temp.c 確實被改為了 12。可見成員變量在運行期并沒有做限制,知道地址就可以繞過編譯器的限制進行讀寫了。那么私有的方法呢?

私有方法和普通成員方法一樣存儲在文本段,我們拿到其地址后,可以通過這個地址調用嗎?這里需要一些騷操作,我們在類定義中添加額外的接口來暴露私有成員方法的地址,然后通過成員函數指針來調用私有成員函數。整體代碼如下:

class Basic {
...
public:
    // 暴露私有成員方法的地址
    static void (Basic::*getSecretPtr())(int) {
        return &Basic::secret;
    }

...
}

int main() {
    // ...
   void (Basic::*funcPtr)(int) = Basic::getSecretPtr();
    // 調用私有成員函數
    (temp.*funcPtr)(10);
    // ...
}

上面代碼正常運行,你可以通過 print 打印調用前后成員變量的值來驗證。看來對于成員函數來說,只是編譯期不讓直接調用,運行期并沒有保護,我們可以繞過編譯限制在對象外部調用。

當然實際開發中,千萬不要直接通過地址偏移來訪問私有成員變量,也不要通過各種騷操作來訪問私有成員方法,這樣不僅破壞了類的封裝性,而且是不安全的。

2.靜態成員

每個熟悉 c++ 類靜態成員的人都知道,靜態成員變量在類的所有實例之間共享,不管你創建了多少個類的對象,靜態成員變量只有一份數據。靜態成員變量的生命周期從它們被定義的時刻開始,直到程序結束。靜態成員方法不依賴于類的任何實例來執行,主要用在工廠方法、單例模式的實例獲取方法、或其他與類的特定實例無關的工具函數。

下面以一個具體的例子,來看看靜態成員變量和靜態成員方法的內存布局以及實現特點。繼續接著前面代碼例子,這里省略掉其他無關代碼了。

#include <iostream>

class Basic {
// ...
public:
    static float alias;
    static void show() {
        std::cout << alias << std::endl;
    }
};

float Basic::alias = 0.233;
int main() {
    // ...
    temp.show();
    return 0;
}

簡單的打印 temp 和 alias 地址,發現兩者之間差異挺大。temp 地址是 0x7fffffffe380,Basic::alias 是 0x555555558048,用 info target 可以看到 alias 在程序的 .data 內存空間范圍 0x0000555555558038 - 0x000055555555804c 內。進一步驗證了下,.data段用于存儲已初始化的全局變量和靜態變量,注意這里需要是非零初始值。

對于沒有初始化,或者初始化為零的全局變量或者靜態變量,是存儲在 .bss 段內的。這個也很好驗證,把上面 alias 的值設為 0,重新查看內存位置,就能看到確實在 .bss 段內了。對于全局變量或者靜態變量,為啥需要分為這兩個段來存儲,而不是合并為一個段來存儲呢?

這里主要是考慮到二進制文件磁盤空間大小以及加載效率。在磁盤上,.data 占用實際的磁盤空間,因為它需要存儲具體的初始值數據。.bss段不占用實際的存儲空間,只需要在程序加載時由操作系統分配并清零相應的內存即可,這樣可以減少可執行文件的大小。在程序啟動時,操作系統可以快速地為.bss段分配內存并將其初始化為零,而無需從磁盤讀取大量的零值數據,可以提高程序的加載速度。這里詳細的解釋也可以參考 Why is the .bss segment required?。

靜態方法又是怎么實現呢?我們先輸出內存地址,發現在 .text 代碼段,這點和其他成員方法是一樣的。不過和成員方法不同的是,第一個參數并不是 this 指針了。在實現上它與普通的全局函數類似,主要區別在于它們的作用域是限定在其所屬的類中。

類繼承的內存布局

當然,既然是在聊面向對象的類,那就少不了繼承了。我們還是從具體例子來看看,在繼承情況下,類的內存布局情況。

1.不帶虛函數的繼承

先來看看不帶虛函數的繼承,示例代碼如下:

#include <iostream>

class Basic {
public:
    int a;
    double b;

    void setB(double value) {
        b = value; // 直接訪問成員變量b
    }
};

class Derived : public Basic {
public:
    int c;
    void setC(int value) {
        c = value; // 直接訪問成員變量c
    }
};

int main() {
    Derived temp;
    temp.a = 10;
    temp.setB(3.14);
    temp.c = 1;
    temp.setC(2);
    return 0;
}

編譯運行后,用 GDB 打印成員變量的內存分布,發現 Derived 類的對象在內存中的布局首先包含其基類Basic的所有成員變量,緊接著是 Derived 類自己的成員變量。整體布局如下圖:

其實 C++ 標準并沒有規定在繼承中,基類和派生類的成員變量之間的排列順序,編譯器可以自由發揮的。但是大部分編譯器在實現中,都是基類的成員變量在派生類的成員變量之前,為什么這么做呢?因為這樣實現,使對象模型變得更簡單和直觀。不論是基類還是派生類,對象的內存布局都是連續的,簡化了對象創建、復制和銷毀等操作的實現。我們通過派生類對象訪問基類成員與直接使用基類對象訪問時完全一致,一個派生類對象的前半部分就是一個完整的基類對象。

對于成員函數(包括普通函數和靜態函數),它們不占用對象實例的內存空間。不論是基類的成員函數還是派生類的成員函數,它們都存儲在程序的代碼段中(.text 段)。

2.帶有虛函數的繼承

帶有虛函數的繼承,稍微有點復雜了。在前面繼承例子基礎上,增加一個虛函數,然后在 main 中用多態的方式調用。

#include <iostream>

class Basic {
public:
    int a;
    double b;

    virtual void printInfo() {
        std::cout << "Basic: a = " << a << ", b = " << b << std::endl;
    }

    virtual void printB() {
        std::cout << "Basic in B" << std::endl;
    }

    void setB(double value) {
        b = value; // 直接訪問成員變量b
    }
};

class Derived : public Basic {
public:
    int c;

    void printInfo() override {
        std::cout << "Derived: a = " << a << ", b = " << b << ", c = " << c << std::endl;
    }

    void setC(int value) {
        c = value; // 直接訪問成員變量c
    }
};

int main() {
    Derived derivedObj;
    derivedObj.a = 10;
    derivedObj.setB(3.14);
    derivedObj.c = 1;
    derivedObj.setC(2);

    Basic* ptr = &derivedObj; // 基類指針指向派生類對象
    ptr->printInfo(); // 多態調用
    ptr->printB(); // 調用

    Basic  basicObj;
    basicObj.a = 10;
    basicObj.setB(3.14);

    Basic* anotherPtr = &basicObj;
    anotherPtr->printInfo();
    anotherPtr->printB();
    return 0;
}

上面代碼中,Basic* ptr = &derivedObj; 這一行用一個基類指針指向派生類對象,當通過基類指針調用虛函數 ptr->printInfo();時,將在運行時解析為 Derived::printInfo() 方法,這是就是運行時多態。對于 ptr->printB(); 調用,由于派生類中沒有定義 printB() 方法,所以會調用基類的 printB() 方法。

那么在有虛函數繼承的情況下,對象的內存布局是什么樣?虛函數的多態調用又是怎么實現的呢?實踐出真知,我們可以通過 GDB 來查看對象的內存布局,在此基礎上可以驗證虛函數表指針,虛函數表以及多態調用的實現細節。這里先看下 Derived 類對象的內存布局,如下圖:

可以看到派生類對象的開始部分(地址 0x7fffffffe370 處)有一個 8 字節的虛函數表指針 vptr(指針地址 0x555555557d80),這個指針指向一個虛函數表(vtable),虛函數表中存儲了虛函數的地址,一共有兩個地址 0x55555555538c 和 0x555555555336,分別對應Derived 類中的兩個虛函數 printInfo 和 printB。基類的情況類似,下面畫一個圖來描述更清晰些:

現在搞清楚了虛函數在類對象中的內存布局。在編譯器實現中,虛函數表指針是每個對象實例的一部分,占用對象實例的內存空間。對于一個實例對象,通過其地址就能找到對應的虛函數表,然后通過虛函數表找到具體的虛函數地址,實現多態調用。那么為什么必須通過引用或者指針才能實現多態調用呢?看下面 3 個調用,最后一個沒法多態調用。

Basic& ref = derivedObj;
Basic* ptr = &derivedObj;
Basic dup = derivedObj; // 沒法實現多態調用

我們用 GDB 來看下這三種對象的內存布局,如下圖:

指針和引用在編譯器底層沒有區別,ref 和 ptr 的地址一樣,就是原來派生類 derivedObj 的地址0x7fffffffe360,里面的虛函數表指針指向派生類的虛函數表,所以可以調用到派生類的 printInfo。而這里的 dup 是通過拷貝構造函數生成的,編譯器執行了隱式類型轉換,從派生類截斷了基類部分,生成了一個基類對象。dup 中的虛函數表指針指向的是基類的虛函數表,所以調用的是基類的 printInfo。

從上面 dup 虛函數表指針的輸出也可以看到,虛函數表不用每個實例一份,所有對象實例共享同一個虛函數表即可。虛函數表是每個多態類一份,由編譯器在編譯時創建。

當然,這里是 Mac 平臺下 Clang 編譯器對于多態的實現。C++ 標準本身沒有規定多態的實現細節,沒有說一定要有虛函數表(vtable)和虛函數表指針(vptr)來實現。這是因為 C++標準關注的是行為和語義,確保我們使用多態特性時能夠得到正確的行為,但它不規定底層的內存布局或具體的實現機制,這些細節通常由編譯器的實現來決定。

不同編譯器的實現也可能不一樣,許多編譯器為了訪問效率,將虛函數表指針放在對象內存布局的開始位置。這樣,虛函數的調用可以快速定位到虛函數表,然后找到對應的函數指針。如果類有多重繼承,情況可能更復雜,某些編譯器可能會采取不同的策略來安排虛函數表指針的位置,或者一個對象可能有多個虛函數表指針。

地址空間布局隨機化

前面的例子中,如果用 GDB 多次運行程序,對象的虛擬內存地址每次都一樣,這是為什么呢?

我們知道現代操作系統中,每個運行的程序都使用虛擬內存地址空間,通過操作系統的內存管理單元(MMU)映射到物理內存的。虛擬內存有很多優勢,包括提高安全性、允許更靈活的內存管理等。為了防止緩沖區溢出攻擊等安全漏洞,操作系統還會在每次程序啟動時隨機化進程的地址空間布局,這就是地址空間布局隨機化(ASLR,Address Space Layout Randomization)。

在 Linux 操作系統上,可以通過 cat /proc/sys/kernel/randomize_va_space 查看當前系統的 ASLR 是否啟用,基本上默認都是開啟狀態(值為 2),如果是 0,則是禁用狀態。

前面使用 GDB 進行調試時,之所以觀察到內存地址是固定不變的,這是因為 GDB 默認禁用了 ASLR,以便于調試過程中更容易重現問題。可以在使用 GDB 時啟用 ASLR,從而讓調試環境更貼近實際運行環境。啟動 GDB 后,可以通過下面命令開啟地址空間的隨機化。

(gdb) set disable-randomization off

之后再多次運行,這里的地址就會變化了。

總結

C++ 的對象模型是一個復雜的話題,涉及到類的內存布局、成員變量和成員函數的訪問、繼承、多態等多個方面。本文從實際例子出發,幫助大家對 C++ 對象的內存布局有了一個直觀的認識。

簡單總結下本文的核心結論:

  • 對象的內存布局是連續的,成員變量按照聲明的順序存儲在對象中,編譯器會根據類定義計算每個成員變量相對于對象起始地址的偏移量。
  • 成員方法存儲在進程的文本段,不占用對象實例的內存空間,通過 this 指針和偏移量訪問成員變量。
  • 私有成員變量和方法在運行期并沒有保護,可以通過地址偏移繞過編譯器的限制進行讀寫,但是不推薦這樣做。
  • 靜態成員變量和靜態成員方法存儲在程序的數據段和代碼段,不占用對象實例的內存空間。
  • 繼承類的內存布局,編譯器一般會把基類的成員變量放在派生類的成員變量之前,使對象模型變得更簡單和直觀。
  • 帶有虛函數的繼承,對象的內存布局中包含虛函數表指針,多態調用通過虛函數表實現。虛函數實現比較復雜,這里只考慮簡單的單繼承。
  • 地址空間布局隨機化(ASLR)是現代操作系統的安全特性,可以有效防止緩沖區溢出攻擊等安全漏洞。GDB 默認禁用 ASLR,可以通過 set disable-randomization off 命令開啟地址空間的隨機化。
責任編輯:趙寧寧 來源: 騰訊技術工程
相關推薦

2022-07-06 08:05:52

Java對象JVM

2023-12-31 12:56:02

C++內存編程

2024-04-10 12:14:36

C++指針算術運算

2022-05-06 16:18:00

Block和 C++OC 類lambda

2024-04-30 08:38:31

C++

2023-09-12 11:44:02

C++數據對齊

2024-04-10 07:40:45

Java虛擬機內存

2023-11-05 12:05:35

JVM內存

2017-03-27 09:36:20

Flex布局計算

2019-10-22 08:11:43

Socket網絡通信網絡協議

2015-12-28 11:25:51

C++異常處理機制

2023-10-04 00:04:00

C++extern

2022-02-16 12:52:22

C++項目編譯器

2020-06-01 21:07:33

C11C++11內存

2021-11-26 00:00:48

JVM內存區域

2024-04-11 14:04:23

C++編程函數

2023-09-19 22:47:39

Java內存

2013-06-20 10:25:56

2020-11-04 15:35:13

Golang內存程序員

2024-01-03 13:38:00

C++面向對象編程OOP
點贊
收藏

51CTO技術棧公眾號

xxxwww国产| 波多野结衣激情| 综合网在线观看| 精品国产一区二区三区四区 | 日本五十路女优| 日韩欧美国产大片| 欧美日韩一区二区不卡| 99久re热视频精品98| 色噜噜在线播放| 久久久夜夜夜| 美日韩在线视频| 精品人妻少妇嫩草av无码| 国产亚洲人成a在线v网站| 亚洲三级免费电影| 久久综合精品一区| av中文字幕第一页| 亚洲中午字幕| 久久av在线看| 欧美多人猛交狂配| 中文字幕一区二区三区四区久久| 色综合久久综合网97色综合| 日韩第一页在线观看| 天堂a中文在线| 久久se精品一区二区| 91精品国产高清| 登山的目的在线| 少妇高潮一区二区三区| 日韩小视频在线观看专区| 99草草国产熟女视频在线| 日本不卡影院| 国产精品丝袜一区| 欧美专区一二三| www.午夜激情| 久久精品国产99| 欧美在线亚洲在线| 精品深夜av无码一区二区老年| 欧美三级三级| 日韩av综合网| 久久久无码人妻精品无码| 成人18视频在线观看| 精品久久久久久久久中文字幕| 中文字幕一区二区三区四区五区人 | 欧美一区在线直播| 激情综合网五月天| 亚洲视频电影在线| 日韩在线观看网址| 久久精品三级视频| 精品日本12videosex| 亚洲精品视频网上网址在线观看| 一本色道久久hezyo无码| 蜜桃精品视频| 91.麻豆视频| 欧美三级午夜理伦三级富婆| 456亚洲精品成人影院| 欧美日韩国产一区在线| 国产素人在线观看| a天堂资源在线| 午夜久久久影院| 欧美成人三级在线视频| 波多野结衣视频一区二区| 亚洲图片欧美色图| 日本福利视频一区| 九九色在线视频| 亚洲综合视频在线| 国产二级片在线观看| 阿v视频在线观看| 婷婷一区二区三区| 情侣黄网站免费看| 日韩免费va| 91黄视频在线| 国产精品嫩草影院8vv8| 经典三级久久| 日韩精品一区二区三区中文不卡 | 麻豆成全视频免费观看在线看| 午夜视黄欧洲亚洲| 欧美色图另类小说| 欧美最新精品| 69堂精品视频| 国产吃瓜黑料一区二区| 黄色欧美在线| 亚洲人精品午夜在线观看| 国产高清一区二区三区四区| 欧美精品久久久久久| 日韩专区在线播放| 免费麻豆国产一区二区三区四区| 在线国产精品一区| 欧美在线性视频| 在线免费看av片| 国产激情偷乱视频一区二区三区| 国产精品一区二区三区观看| 亚洲欧美综合在线观看| 欧美激情一区二区| 免费看黄色a级片| 精品极品在线| 在线观看91精品国产麻豆| 亚洲欧美日韩色| 国产精品片aa在线观看| 久久这里有精品视频| 国产手机在线视频| 轻轻草成人在线| 亚洲综合中文字幕在线观看| 四虎在线免费观看| 《视频一区视频二区| 无码中文字幕色专区| av免费在线一区| 日韩欧美国产三级| 欧美 日韩 成人| 欧美精品九九| 国产精品欧美日韩久久| 亚洲成人一级片| 欧美激情一区二区在线| 日韩精品在线观看av| 日产精品一区| 精品国产91洋老外米糕| 内射毛片内射国产夫妻| 亚洲国产日本| 亚洲一区二区久久久久久| 性xxxx视频播放免费| 亚洲欧美在线aaa| 亚洲国产精品久久久久婷蜜芽| 95精品视频| 亚洲精品综合精品自拍| 免费在线观看日韩| 精品无人区卡一卡二卡三乱码免费卡| 久久国产欧美精品| 欧美色图天堂| 欧美绝品在线观看成人午夜影视| 国内精品久久99人妻无码| 欧美成人日本| 色无极亚洲影院| 日韩精品一区二区三区视频 | 国产毛片aaa| 国产综合久久久久影院| 日韩欧美三级电影| 五月天av在线| 亚洲国产精品久久久久| 欧美又粗又大又长| 另类成人小视频在线| 欧美性天天影院| 精品三级久久| 亚洲成人在线网| 久久久久久久久久久网| 国产又黄又大久久| 在线观看国产一区| 国产成人午夜性a一级毛片| 亚洲天堂第一页| 在线精品免费视| 97精品国产露脸对白| 国产爆乳无码一区二区麻豆| 国产精品亚洲欧美一级在线| 中文在线资源观看视频网站免费不卡| 综合网在线观看| 久久香蕉国产线看观看99| 精品久久久久久久久久中文字幕| 欧美视频三区| 欧美激情在线有限公司| 亚洲AV无码成人片在线观看| 亚洲精品国产a久久久久久| 国产毛片久久久久久| 亚洲欧美偷拍自拍| 91中文字幕在线| 国产素人视频在线观看| 51午夜精品国产| 爱爱视频免费在线观看| 国产一区二区三区久久久| 中文字幕一区二区三区四区五区人| 亚洲高清国产拍精品26u| 久久九九免费视频| 99热这里只有精品在线| 亚洲国产美国国产综合一区二区| 大尺度在线观看| 亚洲日本国产| 欧美精品在线一区| 巨胸喷奶水www久久久免费动漫| 中文字幕日韩av综合精品| 一二区在线观看| 亚洲精选视频在线| 性感美女一区二区三区| 欧美激情自拍| 久久国产精品免费一区| 成人看片网页| 日韩专区在线观看| 国产xxxxxx| 大伊人狠狠躁夜夜躁av一区| 影音先锋男人在线| 国产乱理伦片在线观看夜一区 | 成人影视在线播放| 欧美日本视频在线| 欧美日韩国产精品综合| 久久久久久日产精品| 色一情一区二区三区| 红桃视频欧美| 日本在线播放一区| 警花av一区二区三区| 性欧美xxxx视频在线观看| 韩国三级在线观看久| 制服丝袜激情欧洲亚洲| 日本五十路女优| 中文字幕av一区二区三区免费看 | 九九热这里有精品| 欧美精品久久久久久久免费观看| 邻居大乳一区二区三区| 成人污污视频在线观看| 亚洲午夜精品视频| 无码任你躁久久久久久久| 亚洲色图20p| 毛片网站免费观看| 国产精品456| 国产真人无码作爱视频免费| 雨宫琴音一区二区三区| 欧美日韩亚洲免费| 91成人午夜| 国产精品老女人视频| sqte在线播放| 自拍偷拍亚洲在线| 深夜福利视频在线免费观看| 在线不卡一区二区| 国产精品久久久久久人| 亚洲国产精品一区二区久久| 中文字幕第24页| www.一区二区| 天美一区二区三区| 日本特黄久久久高潮| 国产69精品久久久久999小说| 日韩精品一区二区久久| 久久久久久久久一区| 影音先锋欧美激情| 国产日韩欧美成人| 向日葵视频成人app网址| 国外成人性视频| a级网站在线播放| 中文字幕视频一区二区在线有码| 手机福利小视频在线播放| 欧美妇女性影城| 成人黄色三级视频| 欧美午夜视频一区二区| 国产无码精品在线观看| 亚洲一区在线免费观看| 夫妻性生活毛片| 国产精品美女久久久久久久久久久| 鲁大师私人影院在线观看| 粉嫩av亚洲一区二区图片| 福利视频999| 老司机一区二区| 国产又大又黄又猛| 视频一区视频二区中文| 国产亚洲精品网站| 亚洲麻豆av| 老太脱裤子让老头玩xxxxx| 午夜精品影院| 99久久免费观看| 欧美日韩hd| 在线播放 亚洲| 亚洲国产一区二区在线观看| 一区二区三区四区视频在线观看| 欧美精品一二| 亚洲精品一区国产精品| 欧美va久久久噜噜噜久久| 亚洲精品成人三区| 图片区亚洲欧美小说区| 亚洲小说欧美另类激情| 亚洲精品久久久| 黄色片免费在线观看视频| 韩国av一区| 国产欧美日韩网站| 一本色道久久综合亚洲精品高清| 成年人视频观看| 久久午夜激情| 五月婷婷激情久久| 国产在线不卡一卡二卡三卡四卡| 中文字幕第10页| 国产69精品久久777的优势| 亚洲激情 欧美| 91麻豆免费在线观看| 中文字幕狠狠干| 久久久久久久久伊人| 亚洲一二三四视频| 亚洲女人的天堂| 久草视频精品在线| 一本久道中文字幕精品亚洲嫩| 波多野结衣爱爱| 欧美电影一区二区三区| 老熟妇高潮一区二区高清视频 | 人妻精品一区二区三区| 亚洲精品久久久一区二区三区| 久久电影视频| 久久精品91久久香蕉加勒比| 另类视频在线| 欧美最猛黑人xxxx黑人猛叫黄 | 3d动漫啪啪精品一区二区免费 | 日韩国产精品大片| 思思久久精品视频| 成人国产在线观看| 中文字幕免费高清| 亚洲精品视频免费观看| 天堂网视频在线| 91麻豆精品国产综合久久久久久| 人妻视频一区二区三区| 亚洲人成电影网站色xx| av软件在线观看| 日本道色综合久久影院| 成人污污www网站免费丝瓜| 国产精品综合久久久久久| 清纯唯美日韩| 国产夫妻自拍一区| 蜜臀精品一区二区三区在线观看| 俄罗斯女人裸体性做爰| 久久久99精品免费观看不卡| 丝袜 亚洲 另类 欧美 重口| 狠狠做深爱婷婷久久综合一区| 91精品人妻一区二区三区果冻| 亚洲精品在线电影| 亚洲成人三级| 欧美在线视频免费观看| 久久久久久久久成人| 欧美一区三区二区在线观看| 欧美国产高潮xxxx1819| 国产区二区三区| 91女神在线视频| 欧美日韩在线视频免费| 欧美日韩免费观看一区二区三区| 无码精品人妻一区二区| 欧美高清视频在线播放| 欧美aaa级| 欧美亚洲一级二级| 精品999日本| 欧美日韩中文不卡| 91免费精品国自产拍在线不卡| 免费三级在线观看| 欧洲一区二区三区在线| 日韩av资源| 午夜精品久久久久久久久久久久| 26uuu日韩精品一区二区| 97久久精品| 国产在线无码精品| 麻豆91在线播放| 天美传媒免费在线观看| 色八戒一区二区三区| 日韩欧美在线观看一区二区| 国产69精品久久久久99| 97se亚洲| 韩日视频在线观看| 国产成人综合网| 青青草手机视频在线观看| 欧美日韩国产不卡| h视频在线播放| 国产精品久久久久久久久久久久久久 | 毛片在线播放网址| 欧美一区二区三区免费观看| 免费福利视频一区| 久久黄色片视频| 91视频观看视频| 欧美一区二区三区四| 亚洲激情国产精品| 性国裸体高清亚洲| 久久久久久九九| 久久精品综合| 波多野结衣一本| 91国产福利在线| 国产福利在线| 国产裸体写真av一区二区| 色爱综合网欧美| 欧美大片久久久| 亚洲六月丁香色婷婷综合久久 | 婷婷久久综合网| 日韩精品一区二区三区在线 | www.99在线| 国产精品美女久久久久久久久久久 | 国产91色在线观看| 中文字幕中文字幕一区二区| 国产精品视频久久久久久| 色综合91久久精品中文字幕| 国产+成+人+亚洲欧洲在线| 国产成人无码精品久久久性色| 久久老女人爱爱| 中文字幕日韩三级| 久久精品国产亚洲| 国产精品白丝av嫩草影院| 国产精品沙发午睡系列| 国产欧美一区二区三区网站| 亚洲怡红院av| 欧美极品少妇全裸体| 日本亚洲不卡| 国产三级三级三级看三级| 亚洲婷婷国产精品电影人久久| 精品久久人妻av中文字幕| 91高清免费在线观看| 成人aaaa| 国产精品偷伦视频免费观看了| 欧美日韩国产中字| √天堂资源地址在线官网| 亚洲自拍小视频| 亚洲综合日韩| 中国毛片直接看| 日韩经典第一页| 亚洲欧美在线综合| 欧美极品欧美精品欧美| 国产精品久久久久aaaa| 乱精品一区字幕二区| 国产精品久久久久久久久免费看|