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

編寫你的第一個垃圾收集器

開發 前端
每當我倍感壓力以及有很多事情要做的時候,我總是有這樣一種反常的反應,那就是希望做一些其他的事情來擺脫這種狀況。通常情況下,這些事情都是些我能夠編寫并實現的獨立的小程序。

每當我倍感壓力以及有很多事情要做的時候,我總是有這樣一種反常的反應,那就是希望做一些其他的事情來擺脫這種狀況。通常情況下,這些事情都是些我能夠編寫并實現的獨立的小程序。

一天早上,我幾乎要被一堆事情給整瘋了——我得看一本書、處理一些工作上的事情、還要準備一場Strange Loop的演講,然后這時我突然想到:“我該寫一個垃圾收集器了”。

是的,我知道那一刻讓我看上去有多瘋狂。不過我的神經故障卻是你實現一段基礎的程序語言設計的免費教程!在100行左右毫無新意的c代碼中,我設法實現一個基本的標記和掃描模塊。

垃圾收集被認為是有更多編程牛人出沒的水域之一,但在這里,我會給你一個漂亮的兒童游泳池去玩耍??赡苓@里面仍然會有一些能手,但至少這會是一個淺水區。

 精簡、復用、再復用

垃圾收集背后有這樣一個基本的觀念:編程語言(大多數的)似乎總能訪問無限的內存。而開發者可以一直分配、分配再分配——像魔法一樣,取之不盡用之不竭。

當然,我們從來都沒有無限的內存。所以計算機實現收集的方式就是當機器需要分配一些內存,而內存又不足時,讓它收集垃圾。

“垃圾(Garbage)”在這里表示那些事先分配過但后來不再被使用的內存。而基于對無限內存的幻想,我們需要確保“不再被使用”對于編程語言來說是非常安全的。要知道在你的程序試圖訪問一些隨機的對象時它們卻剛好正在得到回收,這可不是一件好玩的事情。

為了實現收集,編程語言需要確保程序不再使用那個對象。如果該程序不能得到一個對象的引用,那么顯然它也不會再去使用它。所以關于”in use”的定義事實上非常簡單:

  1. 任何被一個變量引用的對象,仍然在作用域內,就屬于”in use”狀態。
  2. 任何被另一個對象引用的對象,仍在使用中,就是”in use”狀態。

如果對象A被一個變量引用,而它又有一些地方引用了對象B,那么B就是在使用中(“in use”),因為你能夠通過A來訪問到它。

這樣到最后的結果就是得到一張可訪問的對象圖——以一個變量為起點并能夠遍歷到的所有對象。任何不在圖中的對象對于程序來說都是死的,而它的內存也是時候被回收了。

 標記并清理

有很多不同的方法可以實現關于查找和回收所有未被使用的對象的操作,但是最簡單也是第一個被提出的算法就是”標記-清除”算法。它由John McCarthy——Lisp(列表處理語言)的發明者提出,所以你現在做的事情就像是與一個古老的神在交流,但希望你別用一些洛夫克拉夫特式的方法——最后以你的大腦和視網膜的完全枯萎而結束。

該算法的工作原理幾乎與我們對”可訪問性(reachability)”的定義完全一樣:

  1. 從根節點開始,依次遍歷整個對象圖。每當你訪問到一個對象,在上面設置一個”標記(mark)”位,置為true。
  2. 一旦搞定,找出所有標記位為”not”的對象集,然后刪除它們。

對,就是這樣。我猜你可能已經想到了,對吧?如果是,那你可能就成為了一位被引用了數百次的文章的作者。所以這件事情的教訓就是,想要在CS(計算機科學)領域中出名,你不必開始就搞出一個很牛的東西,你只需要第一個整出來即可,哪怕這玩意看上去很搓。

對象對

在我們落實這兩個步驟之前,讓我們先做些不相關的準備工作。我們不會為一種語言真正實現一個解釋器——沒有分析器,字節碼、或任何這種愚蠢的東西。但我們確實需要一些少量的代碼來創建一些垃圾去收集。

讓我們假裝我們正在為一種簡單的語言編寫一個解釋器。它是動態類型,并且有兩種類型的變量:int 和 pair。 下面是用枚舉來標示一個對象的類型:

  1. typedef enum { 
  2.   OBJ_INT, 
  3.   OBJ_PAIR 
  4. } ObjectType; 

其中,pair可以是任何一對東西,兩個int、一個int和另一個pair,什么都可以。隨你怎么想都行。因為一個對象在虛擬機中可以是這兩個當中的任意一種類型,所以在c中實現對象的典型方法是時用一個標記聯合體(tagged union)。

  1. typedef struct sObject { 
  2.   ObjectType type; 
  3.   
  4.   union { 
  5.     <span style="color: #999999;">/* OBJ_INT */</span> 
  6.     int value; 
  7.   
  8.    <span style="color: #999999;"> /* OBJ_PAIR */</span> 
  9.     struct { 
  10.       struct sObject* head; 
  11.       struct sObject* tail; 
  12.     }; 
  13.   }; 
  14. } Object; 

這個Object結構擁有一個type字段表示它是哪種類型的值——要么是int要么是pair。接下來用一個union來持有這個int或是pair的數據。如果你對c語言很生疏,一個union就是一個結構體,它將字段重疊在內存中。由于一個給定的對象只能是int或是pair,我們沒有任何理在一個單獨的對象中同時為所有這3個字段分配內存。一個union就搞定。帥吧。

小虛擬機

現在我們可以將其包裝在一個小的虛擬機結構中了。它(指虛擬機)在這里的角色是用一個棧來存儲在當前作用域內的變量。大多數語言虛擬機要么是基于棧 (如JVM和CLR)的,要么是基于寄存器(如Lua)的。但是不管哪種情況,實際上仍然存在這樣一個棧。它用來存放在一個表達式中間需要用到的臨時變量 和局部變量。

我們來簡潔明了地建立這個模型,如下:

  1. #define STACK_MAX 256 
  2.   
  3. typedef struct { 
  4.   Object* stack[STACK_MAX]; 
  5.   int stackSize; 
  6. } VM; 

現在我們得到了一個合適的基本數據結構,接下來我們一起敲些代碼來創建些東西。首先,我們來寫一個方法創建并初始化一個虛擬機:

  1. VM* newVM() { 
  2.   VM* vm = malloc(sizeof(VM)); 
  3.   vm-&gt;stackSize = 0
  4.   return vm; 

一旦我們得到了虛擬機,我們需要能夠操作它的堆棧:

  1. void push(VM* vm, Object* value) { 
  2.   assert(vm-&gt;stackSize &lt; STACK_MAX, "Stack overflow!"); 
  3.   vm-&gt;stack[vm-&gt;stackSize++] = value; 
  4.   
  5. Object* pop(VM* vm) { 
  6.   assert(vm-&gt;stackSize &gt; 0, "Stack underflow!"); 
  7.   return vm-&gt;stack[--vm-&gt;stackSize]; 

好了,現在我們能敲些玩意到”變量”中了,我們需要能夠實際的創建對象。首先來一些輔助函數:

  1. Object* newObject(VM* vm, ObjectType type) { 
  2.   Object* object = malloc(sizeof(Object)); 
  3.   object-&gt;typetype = type; 
  4.   return object; 

它實現了內存的分配和設置類型標記。我們一會兒會重溫它的。利用它,我們可以編寫方法將每種類型的對象壓到虛擬機的棧上:

  1. void pushInt(VM* vm, int intValue) { 
  2.   Object* object = newObject(vm, OBJ_INT); 
  3.   object-&gt;value = intValue
  4.   push(vm, object); 
  5.   
  6. Object* pushPair(VM* vm) { 
  7.   Object* object = newObject(vm, OBJ_PAIR); 
  8.   object-&gt;tail = pop(vm); 
  9.   object-&gt;head = pop(vm); 
  10.   
  11.   push(vm, object); 
  12.   return object; 

這就是我們的小小虛擬機。如果我們有調用這些方法的解析器和解釋器,那我們手上就有了一種對上帝都誠實的語言。而且,如果我們有無限的內存,它甚至能夠運行真正的程序??上г蹅儧]有,所以讓我們來收集些垃圾吧。

標記

第一個階段就是標記(marking)。我們需要掃遍所有可以訪問到的對象,并設置其標志位?,F在我們需要做的第一件事就是為對象添加一個標志位(mark bit):

  1. typedef struct sObject { 
  2.   unsigned char marked; 
  3.   <span style="color: #999999;">/* Previous stuff... */</span> 
  4. } Object; 

一旦我們創建了一個新的對象,我們將修改newObject()方法初始化marked為0。為了標記所有可訪問的對象,我們從內存中的變量入手,這樣就意味著要掃一遍堆棧??瓷先ゾ拖襁@樣:

  1. void markAll(VM* vm) 
  2.   for (int i = 0; i &lt; vm-&gt;stackSize; i++) { 
  3.     mark(vm-&gt;stack[i]); 
  4.   } 

里面又調用了mark。我們來分幾步搭建它。第一:

  1. void mark(Object* object) { 
  2.   object-&gt;marked = 1

毫無疑問,這是最重要的一點。我們標記了這個對象自身是可訪問的,但記住,我們還需要處理對象中的引用:可訪問性是遞歸的。如果該對象是一個pair,它的兩個字段也是可訪問的。操作很簡單:

  1. void mark(Object* object) { 
  2.   object-&gt;marked = 1
  3.   
  4.   if (object-&gt;type == OBJ_PAIR) { 
  5.     mark(object-&gt;head); 
  6.     mark(object-&gt;tail); 
  7.   } 

但是這里有一個bug。你看到了嗎?我們正在遞歸,但我們沒有檢查循環。如果你有一堆pair在一個循環中相互指向對方,這就會造成棧溢出并崩潰。

為了解決這個情況,我們僅需要做的是在訪問到了一個已經處理過的對象時,退出即可。所以完整的mark()方法應該是:

  1. void mark(Object* object) { 
  2.   /* If already marked, we're done. Check this first 
  3.      to avoid recursing on cycles in the object graph. */ 
  4.   if (object->marked) return; 
  5.   
  6.   object->marked = 1
  7.   
  8.   if (object->type == OBJ_PAIR) { 
  9.     mark(object->head); 
  10.     mark(object->tail); 
  11.   } 

現在我們可以調用markAll()方法了,它會準確的標記內存中所有可訪問的對象。我們已經成功一半了!

清理

下一個階段就是清理一遍所有我們已經分配過(內存)的對象并釋放那些沒有被標記過的(對象)。但這里有一個問題:所有未被標記的對象——我們所定義的——都不可達!我們都不能訪問到它們!

虛擬機已經實現了對象引用的語義:所以我們只在變量和pair元素中儲存指向對象的指針。當一個對象不再被任何指針指向時,那我們就完全失去它了,而這也實際上造成了內存泄露。

解決這個問題的訣竅是:虛擬機可以有它自己的對象引用,而這不同于對語言使用者可讀的那種語義。換句話說,我們自己可以保留它們的痕跡。

這么做最簡單的方法是僅維持一張由所有分配過(內存)的對象(組成)的鏈表。我們在這個鏈表中將對象自身擴展為一個節點:

  1. typedef struct sObject { 
  2.   /* The next object in the list of all objects. */ 
  3.   struct sObject* next; 
  4.   
  5.   /* Previous stuff... */ 
  6. } Object; 

虛擬機會保留這個鏈表頭的痕跡:

  1. typedef struct { 
  2.   /* The first object in the list of all objects. */ 
  3.   Object* firstObject; 
  4.   
  5.   /* Previous stuff... */ 
  6. } VM; 

在newVM()方法中我們確保將firstObject初始化為NULL。無論何時創建一個對象,我們都將其添加到鏈表中:

  1. Object* newObject(VM* vm, ObjectType type) { 
  2.   Object* object = malloc(sizeof(Object)); 
  3.   object->typetype = type; 
  4.   object->marked = 0
  5.   
  6.   /* Insert it into the list of allocated objects. */ 
  7.   object->next = vm->firstObject; 
  8.   vm->firstObject = object
  9.   
  10.   return object; 

這樣一來,即便是語言找不到一個對像,它還是可以被實現。想要清理并刪除那些未被標記的對象,我們只需要遍歷該鏈表:

  1. void sweep(VM* vm) 
  2.   Object** object = &vm->firstObject; 
  3.   while (*object) { 
  4.     if (!(*object)->marked) { 
  5.       /* This object wasn't reached, so remove it from the list 
  6.          and free it. */ 
  7.       Object* unreached = *object; 
  8.   
  9.       *object = unreached->next; 
  10.       free(unreached); 
  11.     } else { 
  12.       /* This object was reached, so unmark it (for the next GC) 
  13.          and move on to the next. */ 
  14.       (*object)->marked = 0
  15.       object = &(*object)->next; 
  16.     } 
  17.   } 

這段代碼讀起來有點棘手,因為那個指針(指object)指向的是一個指針,但是通過它的工作你會發現它還是非常簡單的。它只是掃遍了整張鏈表。只要它碰到了一個未被標記的對象,它就會釋放該對象的內存并將其從鏈表中移除。最后,我們將會刪除所有不可訪問的對象。

祝賀你!我們已經有了一個垃圾收集器!現在只剩下一點工作了:實際調用它!首先我們將這兩個階段整合在一起:

  1. void gc(VM* vm) { 
  2.   markAll(vm); 
  3.   sweep(vm); 

沒有比這更明顯的”標記-清除”算法了。現在最棘手的是搞清楚什么時候來實際調用它。”內存不足(low on memory)”是個什么意思?尤其是對于現在的計算機,它們幾乎擁有無限的虛擬內存!

事實證明,我們沒有完全正確或錯誤的答案。這真的取決于你使用虛擬機的目的以及讓它運行在什么樣的硬件上。為了讓這個例子看上去很簡單,我們僅在進行了一定數量的內存分配之后開始收集。事實上一些語言的實現就是這么做的,而這也很容易。

我們將邀請虛擬機來追蹤我們到底創建了多少(對象):

  1. typedef struct { 
  2.   /* The total number of currently allocated objects. */ 
  3.   int numObjects; 
  4.   
  5.   /* The number of objects required to trigger a GC. */ 
  6.   int maxObjects; 
  7.   
  8.   /* Previous stuff... */ 
  9. } VM; 

接下來,初始化:

  1. VM* newVM() { 
  2.   /* Previous stuff... */ 
  3.   
  4.   vm->numObjects = 0
  5.   vm->maxObjects = INITIAL_GC_THRESHOLD
  6.   return vm; 

其中,INITIAL_GC_THRESHOLD為你啟動第一個GC(垃圾收集器)的對象數量。較小的值會更節省內存,而較大的值則更省時。自己看著辦吧。

每當我們創建一個對象,我們增加numObjects,如果它達到最大值就啟動一次收集:

  1. Object* newObject(VM* vm, ObjectType type) { 
  2.   if (vm->numObjects == vm->maxObjects) gc(vm); 
  3.   
  4.   /* Create object... */ 
  5.   
  6.   vm->numObjects++; 
  7.   return object; 

我不會費心的顯示它(指numObjects),但是我們也會稍微調整sweep()方法,每釋放一次就遞減numObjects。最后,我們修改了gc()方法來更新最大值:

  1. void gc(VM* vm) { 
  2.   int numObjects = vm->numObjects; 
  3.   
  4.   markAll(vm); 
  5.   sweep(vm); 
  6.   
  7.   vm->maxObjects = vm->numObjects * 2; 

每次收集之后,我們更新maxObjects——以進行收集后仍在活動的對象為基準。乘法器讓我們的堆隨著活動中的對象數量的增加而增加。同樣,也會隨著一些對象最終被釋放掉而自動減少。

最后

你成功了!如果你全部照做了,那你現在已經得到了一個簡單的垃圾收集算法的句柄。如果你想看完整的代碼,在這里。我再強調一點,盡管這個收集器很簡單,但它可不是一個玩具。

你可以在這上面做一大堆的優化(像在GC和程序設計語言這些事情中,90%的努力都在優化上),但它的核心代碼可是真正的GC。它與目前Ruby和Lua中的收集器非常的相似。你可以使用一些類似的代碼到你的項目中。去做些很酷的事情吧!

原文鏈接:http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/

譯文鏈接:http://blog.jobbole.com/53376/

責任編輯:陳四芳 來源: 伯樂在線
相關推薦

2014-07-24 14:35:26

Linux內核模塊

2019-12-31 08:00:00

DebianLinuxApple Swift

2024-08-26 08:58:50

2024-12-30 08:03:08

2011-07-21 14:54:26

java垃圾收集器

2022-07-25 10:15:29

垃圾收集器Java虛擬機

2021-04-07 13:38:27

Django項目視圖

2022-10-17 10:28:05

Web 組件代碼

2010-03-15 10:37:46

Pthon腳本

2013-01-14 09:44:58

JavaScriptJSJS框架

2021-12-30 11:26:31

語言編譯器腳本

2009-10-30 10:47:48

VB.NET垃圾收集器

2017-09-21 14:40:06

jvm算法收集器

2025-08-26 07:50:22

2023-11-16 08:00:56

Java11G1

2018-10-15 10:10:41

Linux內核補丁

2024-03-27 10:27:35

延遲垃圾收集器

2022-04-19 11:25:31

JVMZGC垃圾收集器

2011-05-10 16:04:45

Java垃圾收集器

2025-07-11 02:33:00

JVM垃圾回收
點贊
收藏

51CTO技術棧公眾號

成人情趣视频| 日韩欧美一中文字暮专区 | 欧美午夜性视频| 亚洲精品久久久久久久久久| 一本色道精品久久一区二区三区 | 亚洲福利一区| 亚洲另类xxxx| 手机版av在线| 蜜桃av在线播放| 国产精品国产三级国产普通话三级| 成人欧美在线观看| 日韩av大片在线观看| 久久密一区二区三区| 欧美成人一区二区三区片免费| 91av资源网| 麻豆系列在线观看| 99久久精品免费观看| 国产精品在线看| 国产一级大片在线观看| 青青草综合网| 亚洲成人免费在线视频| 久久久精品麻豆| sm在线播放| 自拍偷拍欧美精品| 日本一区二区三区四区高清视频| 不卡的日韩av| 蜜桃av一区二区三区| 97激碰免费视频| 波多野结衣欲乱| 中文字幕av一区二区三区人| 日韩网站在线看片你懂的| 一本久道中文无码字幕av| 欧美v亚洲v| 国产精品久久久久久妇女6080 | 日韩www.| 日韩精品在线影院| 佐佐木明希电影| 午夜精品久久久久久毛片| 欧美性猛xxx| 国产xxxx振车| av在线免费网站| 国产精品激情偷乱一区二区∴| 欧美一区二区在线视频观看| 天天爽夜夜爽夜夜爽| 国产99久久久久| 91中文精品字幕在线视频| 亚洲精品一区二区二区| 国产一区91| 91成人在线播放| 日本午夜小视频| 亚洲大胆视频| 久久久噜噜噜久久久| 老湿机69福利| 欧美福利影院| 欧美国产日韩视频| 69av.com| 激情文学一区| 久久久久久久久久久免费 | 国产不卡一区二区三区在线观看| 国产精品玖玖玖| 国精产品一区一区三区mba桃花| 国产精品欧美日韩一区二区| 中文字幕永久在线视频| 免费av网站大全久久| 国产欧美精品在线播放| 国产精选久久久| 国产一区在线不卡| 亚洲伊人一本大道中文字幕| 国产农村妇女毛片精品| 国产精品小仙女| 丁香婷婷久久久综合精品国产| 精品国精品国产自在久不卡| 国产成人午夜精品5599| 国产另类自拍| 国产中文字幕在线看| 国产精品无遮挡| 黄色一级片网址| 日本中文字幕中出在线| 五月天欧美精品| 国产成人综合一区| 视频欧美精品| 欧美成人欧美edvon| 亚洲成年人av| 性欧美lx╳lx╳| 色综久久综合桃花网| 九九视频免费看| 久久动漫亚洲| 91免费人成网站在线观看18| 亚洲欧美国产高清va在线播放| 97精品超碰一区二区三区| 日韩av图片| 18视频在线观看| 欧美日韩亚洲天堂| 激情黄色小视频| 另类春色校园亚洲| 在线电影欧美日韩一区二区私密| 真实国产乱子伦对白在线| 欧美视频官网| 国产成人一区二| 精品国自产在线观看| 久久久精品天堂| 日韩精品一区二区在线视频| 偷拍精品精品一区二区三区| 91麻豆精品91久久久久久清纯| 9.1成人看片| 在线国产一区| 日本久久久久久久久| 99久久精品免费看国产交换| 久久香蕉国产线看观看99| 蜜桃视频成人在线观看| 亚洲一级少妇| 欧美精品1区2区| av小说在线观看| 麻豆国产在线播放| 国产精品久久影院| 成人免费毛片在线观看| 伊人成人在线观看| 天天射天天操天天干| 高清一区二区中文字幕| 亚洲成人中文字幕| 日本xxx免费| 亚洲av毛片成人精品| 盗摄精品av一区二区三区| 久久女同精品一区二区| 欧美唯美清纯偷拍| 日韩免费观看高清完整版在线观看| 国产91在线亚洲| 久久日本片精品aaaaa国产| 国产视频精品久久久| 久久精品这里只有精品| 麻豆视频观看网址久久| 欧美日韩精品免费观看| 激情av在线播放| 欧美精品一二三四| 一级肉体全黄裸片| 亚洲综合不卡| 精品乱色一区二区中文字幕| 羞羞污视频在线观看| 欧美丰满一区二区免费视频| 国产熟女一区二区| 日韩电影网1区2区| 麻豆亚洲一区| 天堂电影一区| 国产视频久久久久| 91蜜桃视频在线观看| 成人丝袜高跟foot| 成人小视频在线观看免费| 成人日韩视频| 欧美成人精品xxx| 国产熟女一区二区三区四区| 成人欧美一区二区三区1314| mm131国产精品| 日韩理论电影| 成人美女免费网站视频| 男人影院在线观看| 欧美疯狂做受xxxx富婆| 日韩va亚洲va欧美va清高| 久久91精品久久久久久秒播 | 精品视频网站| 国产97在线|亚洲| 裸体xxxx视频在线| 在线观看91精品国产入口| 亚洲第一视频区| 美女看a上一区| 中文字幕黄色大片| 老司机亚洲精品一区二区| 免费不卡欧美自拍视频| www.午夜激情| 午夜精品福利一区二区三区蜜桃| 午夜男人的天堂| 久久久久久黄| 性欧美videosex高清少妇| 色999久久久精品人人澡69| 中文字幕日韩精品在线观看| 怡红院成永久免费人全部视频| 国产日韩成人精品| 国产aⅴ爽av久久久久| 中文字幕人成人乱码| 国产二区不卡| 欧美91看片特黄aaaa| 中文字幕亚洲一区在线观看| 97国产成人无码精品久久久| 一区二区欧美在线观看| 欧类av怡春院| 丝袜国产日韩另类美女| 中文字幕在线中文字幕日亚韩一区| 日韩成人18| 2019中文字幕在线| √天堂资源地址在线官网| 欧美一卡二卡在线| 久久夜靖品2区| 国产欧美精品一区二区色综合 | 国产极品久久久久久久久波多结野| 色多多国产成人永久免费网站| 精品国产九九九| 欧美日韩免费在线| 蜜桃av.com| 97se狠狠狠综合亚洲狠狠| 牛夜精品久久久久久久| 国产综合婷婷| 日韩一区免费观看| 97久久综合精品久久久综合| 日韩美女视频中文字幕| 在线观看操人| 亚洲性69xxxbbb| 国精品人妻无码一区二区三区喝尿| 色婷婷综合久久久久中文| 中文字幕亚洲欧美日韩| 国产偷国产偷亚洲高清人白洁| 九色91porny| 日本麻豆一区二区三区视频| 男女猛烈激情xx00免费视频| 99re久久最新地址获取| 久久爱av电影| 色悠久久久久综合先锋影音下载| 国产成人精品国内自产拍免费看| 国产深夜视频在线观看| 久久精品成人欧美大片| 精品久久久久一区二区三区 | 国内av一区二区三区| 精品久久久久久久久久久久久久久久久| 精品久久久久久久久久久国产字幕 | 国产123在线| 91在线看国产| 中文字幕永久免费| 韩国av一区二区三区| 黄色一级免费大片| 久久久久国产精品一区三寸| 精品成在人线av无码免费看| 欧美福利网址| 自拍偷拍一区二区三区| 成人看的视频| 你懂的视频在线一区二区| 久久香蕉精品香蕉| 国产精品我不卡| 久久久91麻豆精品国产一区| 国产精品免费一区豆花| 丁香六月综合| 欧美最猛黑人xxxx黑人猛叫黄| 国产后进白嫩翘臀在线观看视频| 欧美成人sm免费视频| 麻豆视频在线播放| 日韩一区二区精品视频| 成人欧美亚洲| 中文字幕亚洲图片| 视频一区二区三区不卡| 日韩在线视频免费观看高清中文| 啊v视频在线| 综合网中文字幕| 91av资源在线| y97精品国产97久久久久久| 日本美女在线中文版| 日韩综合视频在线观看| 日韩在线免费电影| 久久综合久久美利坚合众国| 在线观看三级视频| 久久男人的天堂| 9999精品成人免费毛片在线看 | 亚洲欧洲激情在线| 加勒比一区二区三区在线| 亚洲天堂男人天堂女人天堂| 国产福利电影在线| 日韩综合中文字幕| 日本在线视频www鲁啊鲁| 欧美激情视频播放| 亚洲精品一区| 国产精品嫩草视频| 国产高清视频一区二区| av色综合网| 欧美黑人做爰爽爽爽| 鲁丝片一区二区三区| 精品少妇av| 国产日韩第一页| 亚洲小说区图片区| 熟女性饥渴一区二区三区| 日本成人在线电影网| 97超碰免费在线观看| 成人蜜臀av电影| 欧美 日韩 国产 成人 在线观看 | 精品亚洲精品福利线在观看| 国产九色在线| 欧美大胆在线视频| bbw在线视频| 国产精品一区二区电影| 中文在线综合| 欧美性大战久久久久| 婷婷亚洲五月| 一区二区传媒有限公司| 天使萌一区二区三区免费观看| 色18美女社区| 久久无码av三级| 农村妇女精品一区二区| 一本高清dvd不卡在线观看| 国产精品久久久久久久免费看| 日韩欧美123| 韩国福利在线| 伦理中文字幕亚洲| 中文字幕一区久| 3d蒂法精品啪啪一区二区免费| 美女视频免费精品| 99热一区二区三区| 久久久精品五月天| 日韩高清一二三区| 久久九九久久九九| 精品无码av在线| 欧美三区免费完整视频在线观看| 女人18毛片水真多18精品| 有码中文亚洲精品| 久草在线资源福利站| 91免费观看网站| 精品一级毛片| 成人性生活视频免费看| 久草这里只有精品视频| 魔女鞋交玉足榨精调教| 亚洲最色的网站| 亚洲一级在线播放| 亚洲美女在线看| av资源在线看片| 91日韩在线视频| 日韩免费久久| 免费观看精品视频| eeuss影院一区二区三区| 国产老头老太做爰视频| 欧美日韩在线一区二区| 日本成人一区| 91av国产在线| 黄色美女久久久| 精品人妻人人做人人爽| 国产一区二区三区不卡在线观看| 青青草华人在线视频| 色婷婷av久久久久久久| 午夜视频在线播放| 久久久久久久久久久免费| 视频一区视频二区欧美| 在线视频精品一区| 久久精品国产亚洲高清剧情介绍| 免费污网站在线观看| 欧美丝袜美女中出在线| 四虎永久在线精品免费网址| 九九精品视频在线观看| gogo大尺度成人免费视频| 亚洲综合欧美日韩| 毛片av一区二区| 自拍偷拍第9页| 欧美日韩一二三区| xxxxx日韩| 国产精品视频99| 久久网站免费观看| 手机版av在线| 亚洲欧美色一区| 99这里有精品视频| 久久99精品国产99久久6尤物| 成人亚洲精品| 日韩中文字幕亚洲精品欧美| 国产成人久久精品77777最新版本 国产成人鲁色资源国产91色综 | 免费大片在线观看| 国产午夜精品一区二区三区四区| 天天操夜夜操视频| 亚洲视频在线观看| 高清av一区二区三区| 一区二区视频在线播放| 精品在线观看视频| 超碰在线国产97| 亚洲电影免费观看高清完整版在线观看| 高清毛片在线观看| 欧美人与性禽动交精品| 日韩电影免费在线看| 成人在线观看高清| 精品免费视频.| 美女扒开腿让男人桶爽久久软| 欧美在线一二三区| 久久国内精品自在自线400部| 好吊色视频在线观看| 亚洲精品国产欧美| 亚洲四虎影院| 黄色一级视频播放| 99久久久久久| 欧美日韩 一区二区三区| 久久精品99久久久久久久久| 9999久久久久| 欧美少妇性生活视频| 中文字幕字幕中文在线中不卡视频| 精品久久无码中文字幕| 97av在线视频免费播放| 欧美综合一区| 亚洲色图欧美另类| 一本色道久久综合亚洲91| 麻豆传媒在线观看| 精品产品国产在线不卡| 日韩av电影天堂| 久久久精品91| 在线播放国产一区中文字幕剧情欧美| 国产一区二区| 男人操女人免费软件| 综合色中文字幕| 日本国产在线| 亚洲r级在线观看| 可以免费看不卡的av网站| 欧美黑人性猛交xxx| 亚洲美女av电影|