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

如何處理JavaScript內存泄露

存儲 存儲軟件 前端
本系列第一篇重點介紹了引擎、運行時、調用棧。第二篇揭示了谷歌V8 JavaScript引擎的內部機制,并且提供了一些關于如何寫出更好的JavaScript代碼的建議。

 幾周前,我們開始寫一個系列,深入探討JavaScript和它的工作原理。我們認為了解JavaScript的構成以及它們如何協作,有助于編寫出更好的代碼和應用程序。

本系列***篇重點介紹了引擎、運行時、調用棧。第二篇揭示了谷歌V8 JavaScript引擎的內部機制,并且提供了一些關于如何寫出更好的JavaScript代碼的建議。

本文作為第三篇,將會討論另一個開發者容易忽視的重要主題 :內存管理。我們也會提供一些關于如何處理JavaScript內存泄露的技巧。在SessionStack,我們需要確保不會造成內存泄露或者不會增加我們集成的Web應用的內存消耗。

[[207675]]

概述

某些語言,比如C有低級的原生內存管理原語,像malloc()和free()。開發人員使用這些原語可以顯式分配和釋放操作系統的內存。

相對地,JavaScript會在創建變量(對象、字符串)時自動分配內存,并在這些變量不被使用時自動釋放內存,這個過程被稱為垃圾回收。這個“自動”釋放資源的特性帶來了很多困惑,讓JavaScript(和其他高級級語言)開發者誤以為可以不關心內存管理。這是一個很大的錯誤

即使使用高級級語言,開發者也應該對于內存管理有一定的理解(至少有基本的理解)。有時自動內存管理存在一些問題(例如垃圾回收實現可能存在缺陷或者不足),開發者必須弄明白這些問題,以便找一個合適解決方法。

內存生命周期

無論你用哪一種編程語言,內存生命周期幾乎總是一樣的:

Here is an overview of what happens at each step of the cycle: 這是對生命周期中的每一步大概的說明:

  • 分配內存— 內存是被操作系統分配,這允許程序使用它。在低級語言中(例如C),這是一個作為開發者需要處理的顯式操作。在高級語言中,然而,這些操作都代替開發者進行了處理。
  • 使用內存。實際使用之前分配的內存,通過在代碼操作變量對內在進行讀和寫。
  • 釋放內存 。不用的時候,就可以釋放內存,以便重新分配。與分配內存操作一樣,釋放內存在低級語言中也需要顯式操作。

想要快速的了解堆棧和內存的概念,可以閱讀本系列***篇文章。

什么是內存

在直接探討Javascript中的內存之前,我們先簡要的討論一下什么是內存、內存大概是怎么樣工作的。

在硬件中,電腦的內存包含了大量的觸發電路,每一個觸發電路都包含一些能夠儲存1位數據的晶體管。觸發器通過唯一標識符來尋址,從而可以讀取和覆蓋它們。因此,從概念上來講,可以認為電腦內存是一個巨大的可讀寫陣列。

人類不善于把我們所有的思想和算術用位運算來表示,我們把這些小東西組織成一個大家伙,這些大家伙可以用來表現數字:8位是一個字節。字節之上是字(16位、32位)。

許多東西被存儲在內存中:

  1. 所有的變量和程序中用到的數據;
  2. 程序的代碼,包括操作系統的代碼。

編譯器和操作系統共同工作幫助開發者完成大部分的內存管理,但是我們推薦你了解一下底層到底發生了什么。

編譯代碼的時候,編譯器會解析原始數據類型,提前計算出它們需要多大的內存空間。然后將所需的數量分配在棧空間中。之所以稱為棧空間,是因在函數被調用的時候,他們的內存被添加在現有內存之上(就是會在棧的最上面添加一個棧幀來指向存儲函數內部變量的空間)。終止的時候,以LIFO(后進先出)的順序移除這些調用。例如:

  1. int n; // 4字節 
  2. int x[4]; // 4個元素的數組,每個元素4字節 
  3. double m; // 8字節 

編譯器馬上知道需要內存 4 + 4 × 4 + 8 = 28字節。

這是當前整型和雙精度的大小。大約20年以前,整型通常只需要2個字節,雙精度需要4個字節,你的代碼不受基礎數據類型大小的限制。

編譯器會插入與操作系統交互的代碼,來請求棧中必要大小的字節來儲存變量。

在上面的例子中,編輯器知道每個變量準確的地址。事實上,無論什么時候我們寫變量n,將會在內部被翻譯成類似“memory address 4127963”的語句。

注意,如果我們嘗試訪問x[4]的內存(開始聲明的x[4]是長度為4的數組,x[4]表示第五個元素),我們會訪問m的數據。那是因為我們正在訪問一個數組里不存在的元素,m比數組中實際分配內存的***一個元素x[3]要遠4個字節,可能***的結果是讀取(或者覆蓋)了m的一些位。這肯定會對其他程序產生不希望產生的結果。

當函數調用其他函數的時候,每一個函數被調用的時候都會獲得自己的棧塊。在自己的棧塊里會保存函數內所有的變量,還有一個程序計數器會記錄變量執行時所在的位置。當函數執行完之后,會釋放它的內存以作他用。

動態分配

不幸的是,事情并不是那么簡單,因為在編譯的時候我們并不知道一個變量將會需要多少內存。假設我們做了下面這樣的事:

  1. int n = readInput(); //讀取用戶的輸入 
  2. ... 
  3. //創建一個有n個元素的數組 

編譯器不知道這個數組需要多少內存,因為數組大小取決于用戶提供的值。

因此,此時不能在棧上分配空間。程序必須在運行時向操作系統請求夠用的空間。此時內存從堆空間中被分配。靜態與動態分配內存之間的不同在下面的表格中被總結出來:

靜態分配內存與動態分配內存的區別。

為了完全理解動態內存是如何分配的,我們需要花更多的時間在指針上,這個可能很大程度上偏離了這篇文章的主題。如果你有興趣學習更多的知識,那就在評論中讓我知道,我就可以在之后的文章中寫更多關于指針的細節。

JavaScript中的內存分配

現在我們來解釋JavaScript中的***步(分配內存)是如何工作的。

JavaScript在開發者聲明值的時候自動分配內存。

  1. var n = 374; // 為數值分配內存 
  2. var s = 'sessionstack'; //為字符串分配內存 
  3.   
  4. var o = { 
  5.   a: 1, 
  6.   b: null 
  7. };  //為對象和它包含的值分配內存 
  8.   
  9. var a = [1, null'str']; //為數組和它包含的值分配內存 
  10.   
  11. function f(a) { 
  12.   return a + 3; 
  13. } //為函數(可調用的對象)分配內存 
  14.   
  15. //函數表達式也會分配一個對象 
  16. someElement.addEventListener('click'function() { 
  17.   someElement.style.backgroundColor = 'blue'
  18. }, false); 
  19.   
  20. //一些函數調用也會導致對象分配 
  21. `var d = new Date(); // allocates a Date object`   //分配一個Date對象的內存 
  22.   
  23. `var e = document.createElement('div');  //分配一個DOM元素的內存 
  24.   
  25. //方法可以分配新的值或者對象 
  26.   
  27. var s1 = 'sessionstack'
  28. var s2 = s1.substr(0, 3);  //s2是一個新的字符串 
  29. // 因為字符串是不可變的 
  30. // JavaScript可能決定不分配內存 
  31. // 而僅僅存儲 0-3的范圍 
  32.   
  33. var a1 = ['str1''str2']; 
  34. var a2 = ['str3''str4']; 
  35. var a3 = a1.concat(a2); 
  36. //新的數組有4個元素是a1和a2連接起來的。 

在JavaScript中使用內存

在JavaScript中使用被分配的內存,本質上就是對內在的讀和寫。

比如,讀、寫變量的值或者對象的屬性,抑或向一個函數傳遞參數。

內存不在被需要時釋放內存

大部分的內存管理問題都在這個階段出現。

這里最難的任務是找出這些被分配的內存什么時候不再被需要。這常常要求開發者去決定程序中的一段內存不在被需要而且釋放它。

高級語言嵌入了一個叫垃圾回收的軟件,它的工作是跟蹤內存的分配和使用,以便于發現一些內存在一些情況下不再被需要,它將會自動地釋放這些內存。

不幸的是,這個過程是一個近似的過程,因為一般關于知道內存是否是被需要的問題是不可判斷的(不能用一個算法解決)。

大部分的垃圾回收器會收集不再被訪問的內存,例如指向它的所有變量都在作用域之外。然而,這是一組可以收集的內存空間的近似值。因為在任何時候,一個內存地址可能還有一個在作用域里的變量指向它,但是它將不會被再次訪問。

垃圾收集

由于找到一些內存是否是“不再被需要的”這個事實是不可判定的,垃圾回收的實現存在局限性。本節解釋必要的概念去理解主要的垃圾回收算法和它們的局限性。

內存引用

垃圾回收算法依賴的主要概念是引用。

在內存管理的語境下,一個對象只要顯式或隱式訪問另一個對象,就可以說它引用了另一個對象。例如,JavaScript對象引用其Prototype(隱式引用),或者引用prototype對象的屬性值(顯式引用)。

在這種情況下,“對象”的概念擴展到比普通JavaScript對象更廣的范圍,并且還包含函數作用域。(或者global詞法作用域)

詞法作用域定義變量的名字在嵌套的函數中如何被解析:內部的函數包含了父級函數的作用域,即使父級函數已經返回。

引用計數垃圾回收

這是最簡單的垃圾回收算法。 一個對象在沒有其他的引用指向它的時候就被認為“可被回收的”。

看一下下面的代碼:

  1. var o1 = { 
  2.   o2: { 
  3.     x: 1 
  4.   } 
  5. }; 
  6.   
  7. //2個對象被創建 
  8. /'o2''o1'作為屬性引用 
  9. //誰也不能被回收 
  10.   
  11. var o3 = o1; //'o3'是第二個引用'o1'指向對象的變量 
  12.   
  13. o1 = 1;      //現在,'o1'只有一個引用了,就是'o3' 
  14. var o4 = o3.o2; // 引用'o3'對象的'o2'屬性 
  15.                 //'o2'對象這時有2個引用: 一個是作為對象的屬性 
  16.                 //另一個是'o4' 
  17.   
  18. o3 = '374'; //'o1'原來的對象現在有0個對它的引用 
  19.              //'o1'可以被垃圾回收了。 
  20.             //然而它的'o2'屬性依然被'o4'變量引用,所以'o2'不能被釋放。 
  21.   
  22. o4 = null;  //最初'o1'中的'o2'屬性沒有被其他的引用了 
  23.            //'o2'可以被垃圾回收了 

循環引用創造麻煩

在涉及循環引用的時候有一個限制。在下面的例子中,兩個對象被創建了,而且相互引用,這樣創建了一個循環引用。它們會在函數調用后超出作用域,應該可以釋放。然而引用計數算法考慮到2個對象中的每一個至少被引用了一次,因此都不可以被回收。

  1. function f() { 
  2.   var o1 = {}; 
  3.   var o2 = {}; 
  4.   o1.p = o2; // o1 引用 o2 
  5.   o2.p = o1; // o2 引用 o1\. 形成循環引用 
  6.   
  7. f(); 

 

標記清除算法

為了決定一個對象是否被需要,這個算法用于確定是否可以找到某個對象。

這個算法包含以下步驟。

  1. 垃圾回收器生成一個根列表。根通常是將引用保存在代碼中的全局變量。在JavaScript中,window對象是一個可以作為根的全局變量。
  2. 所有的根都被檢查和標記成活躍的(不是垃圾),所有的子變量也被遞歸檢查。所有可能從根元素到達的都不被認為是垃圾。
  3. 所有沒有被標記成活躍的內存都被認為是垃圾。垃圾回收器就可以釋放內存并且把內存還給操作系統。

上圖就是標記清除示意。

這個算法就比之前的(引用計算)要好些,因為“一個對象沒有被引用”導致這個對象不能被訪問。相反,正如我們在循環引用的示例中看到的,對象不能被訪問到,不一定不存在引用。

2012年起,所有瀏覽器都內置了標記清除垃圾回收器。在過去幾年中,JavaScript垃圾回收領域中的所有改進(代/增量/并行/并行垃圾收集)都是由這個算法(標記清除法)改進實現的,但并不是對垃圾收集算法本身的改進,也沒有改變它確定對象是否可達這個目標。

推薦一篇文章,其中有關于跟蹤垃圾回收的細節,包括了標記清除法和它的優化算法。

循環引用不再是問題

在上面的例子中(循環引用的那個),在函數執行完之后,這個2個對象沒有被任何可以到達的全局對象所引用。因此,他們將會被垃圾回收器發現為不可到達的。

盡管在這兩個對象之間有相互引用,但是他們不能從全局對象上到達。

垃圾回收器的反常行為

盡管垃圾回收器很方便,但是他們有一套自己的方案。其中之一就是不確定性。換句話說,GC是不可預測的。你不可能知道一個回收器什么時候會被執行。這意味著程序在某些情況下會使用比實際需求還要多的內存。在其他情況下,在特別敏感的應用程序中,可能會出現短停頓。盡管不確定意味著不能確定回收工作何時執行,但大多數GC實現都會在分配內存的期間啟動收集例程。如果沒有內存分配,大部分垃圾回收就保持空閑。參考下面的情況。

  1. 執行相當大的一組分配。
  2. 這些元素中的大部分(或者所有的)都被標記為不可到達的(假設我們清空了一個指向我們不再需要的緩存的引用。)
  3. 沒有更多的分配被執行。

在這種情況下,大多數垃圾回收實現都不會做進一步的回收。換句話說,盡管這里有不可達的引用變量可供回收,回收器也不會管。嚴格講,這不是泄露,但結果卻會占用比通常情況下更多的內存。

什么是內存泄漏

內存泄漏基本上就是不再被應用需要的內存,由于某種原因,沒有被歸還給操作系統或者進入可用內存池。

[[207681]]

編程語言喜歡不同的管理內存方式。然而,一段確定的內存是否被使用是一個不可判斷的問題。換句話說,只有開發者才能弄清楚,是否一段內存可以被還給操作系統。

某些編程語言為開發者提供了釋放內存功能。另一些則期待開發者清楚的知道一段內存什么時候是沒用的。Wikipedia有一篇非常好的關于內存管理的文章。

4種常見的JavaScript內存泄漏

1:全局變量

JavaScript用一個有趣的方式管理未被聲明的變量:對未聲明的變量的引用在全局對象里創建一個新的變量。在瀏覽器的情況下,這個全局對象是window。換句話說:

  1. function foo(arg) { 
  2.     bar = "some text"

等同于

  1. function foo(arg) { 
  2.     window.bar = "some text"

如果bar被假定只在foo函數的作用域里引用變量,但是你忘記了使用var去聲明它,一個意外的全局變量就被聲明了。

在這個例子里,泄漏一個簡單的字符串不會造成很大的傷害,但是它確實有可能變得更糟。

另外一個意外創建全局變量的方法是通過this:

  1. function foo() { 
  2.     this.var1 = "potential accidental global"
  3.   
  4. // Foo作為函數調用,this指向全局變量(window) 
  5. // 而不是undefined 
  6. foo(); 

為了防止這些問題發生,可以在你的JaveScript文件開頭使用'use strict';。這個可以使用一種嚴格的模式解析JavaScript來阻止意外的全局變量。

除了意外創建的全局變量,明確創建的全局變量同樣也很多。這些當然屬于不能被回收的(除非被指定為null或者重新分配)。特別那些用于暫時存儲數據的全局變量,是非常重要的。如果你必須要使用全局變量來存儲大量數據,確保在是使用完成之后為其賦值null或者重新賦其他值。

2: 被遺忘的定時器或者回調

在JavaScript中使用setInterval是十分常見的。

大多數庫,特別是提供觀察器或其他接收回調的實用函數的,都會在自己的實例無法訪問前把這些回調也設置為無法訪問。但涉及setInterval時,下面這樣的代碼十分常見:

  1. var serverData = loadData(); 
  2. setInterval(function() { 
  3.     var renderer = document.getElementById('renderer'); 
  4.     if(renderer) { 
  5.         renderer.innerHTML = JSON.stringify(serverData); 
  6.     } 
  7. }, 5000); //每5秒執行一次 

定時器可能會導致對不需要的節點或者數據的引用。

renderer對象在將來有可能被移除,讓interval處理器內部的整個塊都變得沒有用。但由于interval仍然起作用,處理程序并不能被回收(除非interval停止)。如果interval不能被回收,它的依賴也不可能被回收。這就意味著serverData,大概保存了大量的數據,也不可能被回收。

在觀察者的情況下,在他們不再被需要(或相關對象需要設置成不能到達)的時候明確的調用移除是非常重要的。

在過去,這一點尤其重要,因為某些瀏覽器(舊的IE6)不能很好的管理循環引用(更多信息見下文)。如今,大部分的瀏覽器都能而且會在對象變得不可到達的時候回收觀察處理器,即使監聽器沒有被明確的移除掉。然而,在對象被處理之前,要顯式地刪除這些觀察者仍然是值得提倡的做法。例如:

  1. var element = document.getElementById('launch-button'); 
  2. var counter = 0; 
  3.   
  4. function onClick(event) { 
  5.    counter++; 
  6.    element.innerHtml = 'text ' + counter; 
  7.   
  8. element.addEventListener('click', onClick); 
  9.   
  10. // 做點事 
  11.   
  12. element.removeEventListener('click', onClick); 
  13. element.parentNode.removeChild(element); 
  14.   
  15. // 當元素被銷毀 
  16. //元素和事件都會即使在老的瀏覽器里也會被回收 

如今的瀏覽器(包括IE和Edge)使用現代的垃圾回收算法,可以立即發現并處理這些循環引用。換句話說,先調用removeEventListener再刪節點并非嚴格必要。

jQuery等框架和插件會在丟棄節點前刪除監聽器。這都是它們內部處理,以保證不會產生內存泄漏,甚至是在有問題的瀏覽器(沒錯,IE6)上也不會。

3: 閉包

閉包是JavaScript開發的一個關鍵方面:一個內部函數使用了外部(封閉)函數的變量。由于JavaScript運行時實現的不同,它可能以下面的方式造成內存泄漏:

  1. var theThing = null
  2.   
  3. var replaceThing = function () { 
  4.   
  5.   var originalThing = theThing; 
  6.   var unused = function () { 
  7.     if (originalThing) // 引用'originalThing' 
  8.       console.log("hi"); 
  9.   }; 
  10.   
  11.   theThing = { 
  12.     longStr: new Array(1000000).join('*'), 
  13.     someMethod: function () { 
  14.       console.log("message"); 
  15.     } 
  16.   }; 
  17. }; 
  18.   
  19. setInterval(replaceThing, 1000); 

這段代碼做了一件事:每次ReplaceThing被調用,theThing獲得一個包含大數組和新的閉包(someMethod)的對象。同時,變量unused保持了一個引用originalThing(theThing是上次調用replaceThing生成的值)的閉包。已經有點困惑了吧?最重要的事情是一旦為同一父域中的作用域產生閉包,則該作用域是共享的。

這里,作用域產生了閉包,someMethod和unused共享這個閉包中的內存。unused引用了originalThing。盡管unused不會被使用,someMethod可以通過theThing來使用replaceThing作用域外的變量(例如某些全局的)。而且someMethod和unused有共同的閉包作用域,unused對originalThing的引用強制oriiginalThing保持激活狀態(兩個閉包共享整個作用域)。這阻止了它的回收。

當這段代碼重復執行,可以觀察到被使用的內存在持續增加。垃圾回收運行的時候也不會變小。從本質上來說,閉包的連接列表已經創建了(以theThing變量為根),這些閉包每個作用域都間接引用了大數組,導致大量的內存泄漏。

這個問題被Meteor團隊發現,他們有一篇非常好的文章描述了閉包大量的細節。

4: DOM外引用

有的時候在數據結構里存儲DOM節點是非常有用的,比如你想要快速更新一個表格幾行的內容。此時存儲每一行的DOM節點的引用在一個字典或者數組里是有意義的。此時一個DOM節點有兩個引用:一個在dom樹中,另外一個在字典中。如果在未來的某個時候你想要去移除這些排,你需要確保兩個引用都不可到達。

  1. var elements = { 
  2.     button: document.getElementById('button'), 
  3.     image: document.getElementById('image'
  4. }; 
  5.   
  6. function doStuff() { 
  7.     image.src = 'http://example.com/image_name.png'
  8.   
  9. function removeImage() { 
  10.     //image是body元素的子節點 
  11.     document.body.removeChild(document.getElementById('image')); 
  12.   
  13.     //這個時候我們在全局的elements對象里仍然有一個對#button的引用。 
  14.     //換句話說,buttom元素仍然在內存中而且不能被回收。 

當涉及DOM樹內部或子節點時,需要考慮額外的考慮因素。例如,你在JavaScript中保持對某個表的特定單元格的引用。有一天你決定從DOM中移除表格但是保留了對單元格的引用。人們也許會認為除了單元格其他的都會被回收。實際并不是這樣的:單元格是表格的一個子節點,子節點保持了對父節點的引用。確切的說,JS代碼中對單元格的引用造成了整個表格被留在內存中了,所以在移除有被引用的節點時候要當心。

我們在SessionStack努力遵循這些***實踐,因為:

一旦你整合essionStack到你的生產應用中,它就開始記錄所有的事情:DOM變化、用戶交互、JS異常、堆棧跟蹤、失敗的網絡請求、調試信息,等等。

通過SessionStack,你可以回放應用中的問題,看到問題對用戶的影響。所有這些都不會對你的應用產生性能的影響。因為用戶可以重新加載頁面或者在應用中跳轉,所有的觀察者、攔截器、變量分配都必須合理處置。以免造成內存泄漏,也預防增加整個應用的內存占用。

這是一個免費的計劃,你現在可以嘗試一下。

 


 

 

責任編輯:武曉燕 來源: 前端大全
相關推薦

2017-12-11 11:00:27

內存泄露判斷

2018-11-21 12:27:21

JavaScript 貨幣值區域

2017-05-04 16:07:11

Tomcat內存泄露

2016-05-25 10:03:51

JavaScript內存泄露

2019-08-15 10:20:19

云計算技術安全

2012-12-12 09:49:41

2020-12-29 09:11:33

LinuxLinux內核

2017-03-13 13:21:34

Git處理大倉庫

2019-12-23 10:20:12

Web圖片優化前端

2021-03-01 07:31:53

消息支付高可用

2024-03-26 09:40:53

Linux優化

2015-12-07 09:39:27

Java內存泄露

2023-07-03 13:50:13

ReactonResize事件

2021-05-31 10:47:17

SpringSecuritySession

2024-08-26 10:47:22

2022-04-19 09:00:52

ReactTypeScript

2010-05-17 10:04:45

2024-04-16 13:32:57

2023-01-04 10:01:21

ReactTypeScript元素

2011-02-28 14:08:31

網速變慢局域網網速
點贊
收藏

51CTO技術棧公眾號

免费欧美日韩| 久久夜色精品国产噜噜av小说| 亚洲国产成人私人影院tom| 国产精品羞羞答答| www.av视频| 天天操综合520| 欧美三级视频在线| 屁屁影院ccyy国产第一页| 视频一区二区三区国产| 日韩精品视频网站| 久久99国产综合精品女同| 黄色a一级视频| 伊人久久大香伊蕉在人线观看热v| 一区二区三区精品视频| 免费在线成人av电影| 97成人在线观看| 日韩午夜在线| 日韩中文字幕av| 成人做爰www看视频软件| 久久青青视频| 亚洲综合丁香婷婷六月香| 日本成人黄色| 男人天堂综合网| 久久草av在线| 青青草原成人在线视频| 欧美毛片在线观看| 日韩欧美视频在线播放| 日韩久久精品成人| 亚洲国产精品狼友在线观看| 色综合视频一区二区三区日韩| 疯狂蹂躏欧美一区二区精品| 美女在线免费视频| 在线免费av电影| 久久美女高清视频 | 精品久久国产一区| 欧洲一区在线电影| 欧美在线观看成人| av有码在线观看| 亚洲男人天堂av网| 亚洲精品日韩精品| 久久久久久久影视| 91麻豆.com| 狠狠综合久久av| 国产 欧美 自拍| 国产乱一区二区| 国产原创欧美精品| 在线免费观看一级片| 久久精品导航| 全球成人中文在线| 六月丁香在线视频| 国产色综合网| 97超碰国产精品女人人人爽| 国产乡下妇女做爰视频| 亚洲视频免费| 欧美大片在线看| 国产女人被狂躁到高潮小说| 中文字幕一区二区三三| 精品国模在线视频| 国产午夜手机精彩视频| 911精品美国片911久久久| 久久久999成人| 国产美女久久久久久| 国产精品久久久久久久| 两个人的视频www国产精品| 国精品人伦一区二区三区蜜桃| 日韩欧美高清| 另类少妇人与禽zozz0性伦| 免费成人深夜夜行网站| 欧美一区二区三区另类| 欧美大片在线免费观看| 国产在线视频二区| 国产欧美日韩一级| 国产成人免费91av在线| 日本视频www色| 久久97超碰国产精品超碰| 91午夜在线播放| 亚洲伦理在线观看| 91视频国产资源| 日韩妆和欧美的一区二区| 高清美女视频一区| 亚洲欧美日韩中文字幕一区二区三区| 好吊色这里只有精品| 三级资源在线| 黑人与娇小精品av专区| 无码日韩人妻精品久久蜜桃| 久久久免费人体| 日韩欧美国产一区二区在线播放 | 久久你懂得1024| 亚洲国产精品日韩| 羞羞的网站在线观看| 偷偷要91色婷婷| 美女一区二区三区视频| 欧美日韩黄网站| 国产丝袜精品视频| 视频国产一区二区| 国产视频一区三区| 国产日本欧美一区二区三区在线| 精品久久久无码中文字幕| 99re66热这里只有精品3直播| 日本一区二区三区视频免费看| 黄网站视频在线观看| 精品电影在线观看| 日韩欧美亚洲另类| 欧美美女在线直播| 久久好看免费视频| 九九九在线观看| 国模娜娜一区二区三区| 久久99精品久久久久久秒播放器| 国产黄色在线| 午夜电影久久久| 玖玖爱视频在线| 亚洲婷婷丁香| 欧美国产日本高清在线| 中文字幕二区三区| 26uuu亚洲| 久草视频这里只有精品| 免费成人毛片| 亚洲精品一区二区网址| 久青草免费视频| 美女网站色91| 欧美少妇一区| 18video性欧美19sex高清| 4438成人网| 女人十八毛片嫩草av| 亚洲激情在线| 91在线短视频| 视频三区在线| 在线国产电影不卡| 久久中文字幕人妻| 99亚洲伊人久久精品影院红桃| 成人精品久久一区二区三区| 极品白浆推特女神在线观看 | 国产老熟妇精品观看| 日韩精品一区二区三区中文| 中文字幕日韩在线观看| 日韩精选在线观看| 久久久久九九视频| 97在线播放视频| 老司机aⅴ在线精品导航| 欧美精品videossex88| 国产成人毛毛毛片| 亚洲美女在线一区| 九九久久久久久| 99久久.com| 成人av在线网址| 尤物网址在线观看| 欧美日韩国产123区| 国产一级久久久久毛片精品| 久久久国产精品一区二区中文| 久久99国产精品| 亚洲妇女成熟| 亚洲人成亚洲人成在线观看| 免费看毛片网站| 久久尤物电影视频在线观看| 国产精品沙发午睡系列| 日韩高清一级| 青青草原一区二区| 成人av毛片| 欧美乱妇23p| 欧美偷拍第一页| 国产精品一卡二卡| 欧美精品自拍视频| 日韩中文av| 国产精品高清在线| 日本视频在线免费观看| 欧美精品v日韩精品v韩国精品v| 免费高清在线观看电视| 国产成人日日夜夜| 日韩精品 欧美| 制服丝袜日韩| 国产精品一区二区性色av| 精品黄色免费中文电影在线播放| 欧美一区二区三区啪啪| 免费网站观看www在线观| 成人精品视频一区二区三区| 黄色网页免费在线观看| 国产欧美日韩影院| 成人福利网站在线观看11| 性欧美猛交videos| 日韩黄色在线免费观看| 久久久久精彩视频| 亚洲欧美日韩国产中文在线| 亚洲午夜久久久久久久久| 国产亚洲精品久久久久婷婷瑜伽| 日本午夜精品一区二区三区| 国产95亚洲| 91精品国产网站| avav免费在线观看| 精品国产伦理网| 精品成人无码久久久久久| 亚洲欧美激情小说另类| 亚洲国产综合视频| 极品美女销魂一区二区三区免费 | 欧美人与性动交α欧美精品济南到 | 国产精品免费入口| 久久电影院7| 国产精品手机在线| 久久爱.com| 韩国视频理论视频久久| aiai在线| 日韩精品视频在线观看免费| 国产一区二区三区中文字幕 | 亚洲av综合一区| 亚洲成人免费电影| 亚洲 欧美 国产 另类| 99久久99久久综合| 中文字幕亚洲影院| 久久久久久自在自线| 成人毛片100部免费看| 欧美日韩一二三四| 99久久伊人精品影院| www.久久| 欧洲中文字幕国产精品| 91精品国产91久久久久久青草| 亚洲欧美精品一区二区| www久久久久久| 欧美日韩一区二区不卡| 精品国产免费观看| 依依成人综合视频| 日本一二三不卡视频| 91在线你懂得| 日本人妻一区二区三区| 国产又黄又大久久| 日韩欧美黄色大片| 免费看的黄色欧美网站| 99视频在线免费播放| 影音国产精品| 黄色一级片av| 91精品国产福利在线观看麻豆| 日本婷婷久久久久久久久一区二区| 久久97精品| 国产精品污www一区二区三区| 在线欧美激情| 国产在线一区二区三区| 免费污视频在线一区| 青青草原一区二区| 成人片免费看| 欧美最猛性xxxxx(亚洲精品)| 嗯~啊~轻一点视频日本在线观看| 久久亚洲一区二区三区四区五区高| 91精品大全| 色悠悠久久久久| aiai在线| 久久精品国产91精品亚洲| 色影院视频在线| 日韩中文字幕视频在线| 麻豆视频免费在线观看| 久久视频国产精品免费视频在线 | 亚洲品质自拍视频| fc2ppv在线播放| 亚洲人成网站精品片在线观看| 情侣偷拍对白清晰饥渴难耐| 亚洲欧洲另类国产综合| 日韩在线视频网址| 一区二区三区影院| 久久9999久久免费精品国产| 午夜精品久久久久久久99樱桃| 国产精品suv一区二区69| 午夜视黄欧洲亚洲| 在线观看日本视频| 在线观看91视频| 91麻豆国产视频| 日韩美一区二区三区| 日本精品999| 亚洲老头老太hd| 在线免费黄色| 欧美放荡办公室videos4k| 免费在线看污片| 欧美在线视频一区| 国产亚洲人成a在线v网站| 91视频免费在线| 国产劲爆久久| 日韩美女一区| 91超碰成人| 少妇高潮毛片色欲ava片| 日一区二区三区| 国产精品探花在线播放| 波多野结衣中文字幕一区| xxxx日本免费| 亚洲激情图片qvod| 国产欧美一区二区三区在线看蜜臂| 91国产视频在线观看| 国产精品久久综合青草亚洲AV| 欧美变态tickle挠乳网站| 四虎影视精品成人| 中文字幕精品国产| 日本天码aⅴ片在线电影网站| 777午夜精品福利在线观看| 78精品国产综合久久香蕉| www久久99| 精品99在线| 日韩免费在线观看av| 青青青伊人色综合久久| 真实乱偷全部视频| 国产午夜精品美女毛片视频| 久久国产美女视频| 欧美日韩国产精品一区| 最好看的日本字幕mv视频大全 | 深夜福利视频一区| 在线观看91久久久久久| 黄色羞羞视频在线观看| 国产精品扒开腿做爽爽爽的视频| 综合伊人久久| 色噜噜一区二区| 国一区二区在线观看| 污污网站免费观看| 99re66热这里只有精品3直播| 欧美做爰爽爽爽爽爽爽| 欧美日韩中文字幕日韩欧美| 97人妻精品一区二区三区动漫| 日韩av一区二区在线观看| 香蕉视频免费在线播放| 欧美性受xxxx白人性爽| 日韩视频在线直播| 亚洲欧美日产图| 欧美在线综合| 99久久免费看精品国产一区| 亚洲欧洲av色图| 日韩电影在线观看一区二区| 亚洲国产一区自拍| 91麻豆一二三四在线| 91日韩在线视频| 欧美日韩在线网站| 久久精品免费一区二区| 不卡av免费在线观看| 国模无码国产精品视频| 欧美性大战久久久久久久蜜臀| 亚洲 欧美 激情 另类| 欧美激情精品久久久久久黑人| 亚洲高清影院| 亚洲乱码一区二区三区| 日韩精品欧美成人高清一区二区| 91视频在线免费| 午夜不卡在线视频| 蜜臀av中文字幕| 欧美激情国内偷拍| 午夜久久av| 成人午夜视频免费观看| 国产一区二区中文字幕| 麻豆精品国产免费| 欧美日本在线播放| 九色porny丨首页在线| 91精品国产综合久久男男| 欧美艳星介绍134位艳星| 日本一极黄色片| 久久久www成人免费毛片麻豆| 日韩特黄一级片| 亚洲乱码一区av黑人高潮| 国内激情视频在线观看| 国内精品**久久毛片app| 日韩视频久久| 欧美成人三级伦在线观看| 粉嫩老牛aⅴ一区二区三区 | 久久久久国产免费免费 | 亚洲www色| 成人情视频高清免费观看电影| 国产精品www.| 9.1在线观看免费| 亚洲福利国产精品| 天堂资源最新在线| 国产成人精品av在线| 成人黄色av| 天堂av8在线| 亚洲精品乱码久久久久久 | 成人午夜电影小说| 日本少妇性高潮| 精品呦交小u女在线| 免费污视频在线一区| 一区二区免费在线视频| 国产精品一区二区在线观看不卡 | 91精品国产综合久久久久久久| 麻豆91在线| 国产精品sss| 久久综合图片| 国产视频精品免费| 精品三级av在线| 伊人久久av| 99久久久无码国产精品性色戒| 东方欧美亚洲色图在线| 国产精品va无码一区二区三区| 中文字幕日韩av电影| 国产午夜亚洲精品一级在线| 亚洲 自拍 另类小说综合图区| 久久女同性恋中文字幕| 国产精品爽爽久久久久久| 久久久久久999| 欧美精选一区二区三区| 被黑人猛躁10次高潮视频| 精品国产91乱高清在线观看| 国产一级免费在线观看| 亚洲自拍偷拍一区| 亚洲欧美日韩国产| 精品国产精品国产精品| 亚洲国产日韩欧美在线动漫| 欧美综合影院| 久久久999视频| 亚洲精品网站在线观看| 香蕉久久一区二区三区| 91免费高清视频| 久久精品中文|