久久亚洲成a人片熟女精品色一区二区三区|国产精品视频第一精品视频|av天堂热无码手机版|亚洲?v无码久久无遮挡|国产精品偷伦视频免费观看国产|麻豆国产自产精品丰满熟妇|av无码av不卡一区二区|久久亚洲精品中文字

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營的一線實(shí)戰(zhàn)洞察。

Android性能優(yōu)化:SparseArray與ArrayMap替代HashMap的深度解析

Android性能優(yōu)化:SparseArray與ArrayMap替代HashMap的深度解析 1. 從一個(gè)真實(shí)的性能問題說起做Android開發(fā)有些年頭的人大概率都經(jīng)歷過這樣一種場景某個(gè)列表頁在低端機(jī)上滑動(dòng)起來就是不夠跟手幀率時(shí)不時(shí)掉到40以下明明邏輯不復(fù)雜Adapter里也沒做什么耗時(shí)操作但Profiler一掛上去GC日志刷得跟流水賬一樣。順著內(nèi)存分配一路追下去最后發(fā)現(xiàn)罪魁禍?zhǔn)准炔皇菆D片加載也不是網(wǎng)絡(luò)請(qǐng)求而是某個(gè)用HashMapInteger, Object存了幾百條映射關(guān)系的緩存結(jié)構(gòu)。這個(gè)結(jié)論第一次看到的時(shí)候確實(shí)有點(diǎn)反直覺。HashMap在Java世界里幾乎是萬能容器的代名詞怎么到了Android上就成了性能瓶頸原因其實(shí)不復(fù)雜HashMap每個(gè)鍵值對(duì)都要額外創(chuàng)建一個(gè)Entry對(duì)象而Integer作為key在自動(dòng)裝箱時(shí)又會(huì)產(chǎn)生臨時(shí)對(duì)象。一個(gè)幾百條數(shù)據(jù)的Map在頻繁讀寫場景下短時(shí)間內(nèi)就能制造出成千上萬個(gè)小對(duì)象GC壓力自然就上來了。Android的Dalvik和ART雖然一直在優(yōu)化GC但內(nèi)存分配這件事本身的開銷是躲不掉的。SparseArray和ArrayMap就是在這個(gè)背景下進(jìn)入視野的。它們不是Android獨(dú)創(chuàng)的什么黑科技本質(zhì)上是用時(shí)間換空間的經(jīng)典思路放棄HashMap的哈希桶結(jié)構(gòu)改用有序數(shù)組加二分查找來存儲(chǔ)鍵值對(duì)。查找從O(1)退化到O(log n)但省掉了Entry對(duì)象和裝箱開銷在小數(shù)據(jù)量場景下綜合表現(xiàn)反而更好。這個(gè)取舍值不值得取決于你的數(shù)據(jù)規(guī)模和讀寫比例不能一概而論。這篇文章會(huì)把這兩個(gè)容器從設(shè)計(jì)動(dòng)機(jī)、內(nèi)部結(jié)構(gòu)、核心方法實(shí)現(xiàn)、性能邊界到實(shí)際選型完整地拆一遍。適合已經(jīng)寫過一段時(shí)間Android、對(duì)Java集合有一定了解、但還沒系統(tǒng)研究過這兩個(gè)類的開發(fā)者??赐曛竽銘?yīng)該能判斷什么場景該用SparseArray什么場景該用ArrayMap什么場景老老實(shí)實(shí)回去用HashMap。2. 為什么Android要另起爐灶2.1 HashMap在移動(dòng)端的三個(gè)隱性成本要理解SparseArray和ArrayMap的價(jià)值得先把HashMap在Android上的成本算清楚。很多人只知道“HashMap快”但快是有代價(jià)的這個(gè)代價(jià)在服務(wù)端可能無所謂在移動(dòng)端就會(huì)被放大。第一個(gè)成本是Entry對(duì)象的額外內(nèi)存。HashMap內(nèi)部維護(hù)一個(gè)Node數(shù)組Java 8之后是Node之前是Entry每個(gè)鍵值對(duì)都要包裝成一個(gè)Node對(duì)象里面存hash、key、value和next指針。一個(gè)Node對(duì)象在32位JVM上大約占32字節(jié)64位開啟指針壓縮后大約40字節(jié)左右。如果你存1000條數(shù)據(jù)光Node對(duì)象就是40KB這還沒算數(shù)組本身的容量。第二個(gè)成本是自動(dòng)裝箱。HashMapInteger, Object里的key是Integer類型當(dāng)你寫map.put(1, obj)的時(shí)候字面量1會(huì)被自動(dòng)裝箱成Integer.valueOf(1)。雖然Integer有-128到127的緩存池但超過這個(gè)范圍的整數(shù)每次都會(huì)new一個(gè)新對(duì)象。在循環(huán)里頻繁put/get裝箱產(chǎn)生的臨時(shí)對(duì)象數(shù)量相當(dāng)可觀。第三個(gè)成本是擴(kuò)容時(shí)的rehash。HashMap默認(rèn)容量16負(fù)載因子0.75超過閾值就擴(kuò)容翻倍。擴(kuò)容時(shí)所有元素都要重新計(jì)算hash并重新分配位置這個(gè)操作在數(shù)據(jù)量大時(shí)會(huì)造成明顯的卡頓。雖然可以通過預(yù)設(shè)初始容量來緩解但很多開發(fā)者并不會(huì)這么做。注意這里說的成本是相對(duì)的。如果你的Map只有幾十條數(shù)據(jù)或者讀寫頻率很低HashMap的這些開銷完全可以忽略。不要為了優(yōu)化而優(yōu)化先測量再動(dòng)手。2.2 SparseArray的設(shè)計(jì)取舍SparseArray的全稱是android.util.SparseArray它的key被限定為int類型value是泛型Object。這個(gè)限定不是限制而是它的核心設(shè)計(jì)前提。因?yàn)閗ey是int就不需要裝箱也不需要計(jì)算hashCode。SparseArray內(nèi)部維護(hù)兩個(gè)平行數(shù)組一個(gè)int[] mKeys存放鍵一個(gè)Object[] mValues存放值。所有鍵按升序排列查找時(shí)用二分查找定位。這個(gè)設(shè)計(jì)帶來的直接好處是沒有Entry對(duì)象沒有裝箱內(nèi)存占用大幅降低。代價(jià)是查找從O(1)變成O(log n)插入和刪除因?yàn)橐苿?dòng)數(shù)組元素最壞情況是O(n)。SparseArray還有一個(gè)變體叫SparseIntArray、SparseLongArray、SparseBooleanArray分別對(duì)應(yīng)value是基本類型的場景。這些變體連value的裝箱都省了在統(tǒng)計(jì)計(jì)數(shù)、狀態(tài)標(biāo)記這類場景下非常實(shí)用。2.3 ArrayMap的通用化嘗試SparseArray的key只能是int這個(gè)限制在很多場景下不夠用。比如你想用String做keySparseArray就無能為力了。ArrayMap就是為了解決這個(gè)問題而出現(xiàn)的。ArrayMap同樣使用兩個(gè)平行數(shù)組但key是Object類型可以是String、Integer或任何對(duì)象。它內(nèi)部維護(hù)一個(gè)int[] mHashes數(shù)組存放key的hashCode以及Object[] mArray數(shù)組交替存放key和value。查找時(shí)先對(duì)mHashes做二分查找找到后再比較key的equals。ArrayMap在Android 5.0之后被加入androidx.collection包也可以在非Android項(xiàng)目中使用。它的設(shè)計(jì)目標(biāo)是在數(shù)據(jù)量較小通常小于1000且讀多寫少的場景下提供比HashMap更低的內(nèi)存占用。2.4 三者的核心差異對(duì)比特性HashMapSparseArrayArrayMapkey類型任意Objectint任意Object數(shù)據(jù)結(jié)構(gòu)哈希桶鏈表/紅黑樹有序int數(shù)組Object數(shù)組有序hash數(shù)組鍵值交替數(shù)組查找復(fù)雜度O(1)平均O(log n)O(log n)插入復(fù)雜度O(1)平均O(n)最壞O(n)最壞內(nèi)存占用高Entry裝箱低中無Entry有hash數(shù)組適用數(shù)據(jù)量任意小于1000小于1000線程安全否否否這張表是選型的核心依據(jù)。記住一個(gè)原則數(shù)據(jù)量小、讀多寫少、key是int優(yōu)先SparseArraykey不是int但數(shù)據(jù)量小考慮ArrayMap數(shù)據(jù)量大或?qū)懖僮黝l繁老老實(shí)實(shí)用HashMap。3. SparseArray內(nèi)部結(jié)構(gòu)深度拆解3.1 二分查找的實(shí)現(xiàn)細(xì)節(jié)SparseArray的查找邏輯集中在ContainerHelpers.binarySearch這個(gè)方法里。它的實(shí)現(xiàn)很樸素就是標(biāo)準(zhǔn)的二分查找但有一個(gè)細(xì)節(jié)值得注意當(dāng)找不到目標(biāo)時(shí)它返回的是目標(biāo)應(yīng)該插入位置的按位取反值。static int binarySearch(int[] array, int size, int value) { int lo 0; int hi size - 1; while (lo hi) { final int mid (lo hi) 1; final int midVal array[mid]; if (midVal value) { lo mid 1; } else if (midVal value) { hi mid - 1; } else { return mid; } } return ~lo; }這個(gè)~lo的返回值設(shè)計(jì)很巧妙。調(diào)用方拿到負(fù)數(shù)就知道沒找到再取反就得到應(yīng)該插入的位置。put方法就是靠這個(gè)機(jī)制來保證數(shù)組始終有序的。實(shí)操心得如果你自己實(shí)現(xiàn)類似的有序數(shù)組結(jié)構(gòu)這個(gè)“返回插入點(diǎn)”的技巧可以直接抄。它避免了查找和插入兩次遍歷在put操作里能省一次二分查找。3.2 put方法的完整流程put方法的邏輯可以拆成幾種情況數(shù)組為空或size為0直接放在索引0二分查找key如果找到直接替換value如果沒找到拿到插入位置判斷是否需要擴(kuò)容如果需要擴(kuò)容先擴(kuò)容再插入如果不需要擴(kuò)容用System.arraycopy把插入位置之后的元素整體后移一位在插入位置寫入key和valuesize加一這里的關(guān)鍵點(diǎn)是數(shù)組移動(dòng)。每次插入新key都要把插入點(diǎn)之后的所有元素后移。如果一直往數(shù)組頭部插入每次都是O(n)的移動(dòng)性能會(huì)急劇下降。所以SparseArray適合的是key分布相對(duì)均勻、插入不集中在頭部的場景。擴(kuò)容策略也值得說一下。SparseArray的初始容量是10擴(kuò)容時(shí)如果當(dāng)前size小于等于4就擴(kuò)到8否則擴(kuò)到size的2倍。這個(gè)策略比HashMap的翻倍擴(kuò)容更保守因?yàn)镾parseArray的數(shù)據(jù)量本來就不大。3.3 delete與remove的差異SparseArray有兩個(gè)刪除方法delete和remove。它們內(nèi)部都調(diào)用同一個(gè)方法但語義上有區(qū)別。delete方法在刪除后如果數(shù)組大小超過一定閾值會(huì)調(diào)用gc方法壓縮數(shù)組。gc方法會(huì)把所有非空的值往前移動(dòng)消除中間的空洞。remove方法在API 24之后和delete合并了行為一致。但要注意SparseArray的刪除并不是立即把數(shù)組縮短而是把對(duì)應(yīng)位置的值置為DELETED標(biāo)記一個(gè)靜態(tài)空對(duì)象然后size減一。真正的數(shù)組壓縮發(fā)生在gc調(diào)用時(shí)。這個(gè)設(shè)計(jì)是為了避免每次刪除都移動(dòng)數(shù)組把多次刪除的移動(dòng)成本合并到一次gc里。public void delete(int key) { int i ContainerHelpers.binarySearch(mKeys, mSize, key); if (i 0) { mValues[i] DELETED; mGarbage true; } }注意如果你在遍歷SparseArray的過程中刪除元素要小心DELETED標(biāo)記的影響。雖然size已經(jīng)減一但底層數(shù)組里可能還有DELETED占位。用size作為循環(huán)邊界是安全的但不要直接訪問mValues數(shù)組。3.4 append方法的優(yōu)化場景SparseArray提供了一個(gè)append方法專門用于key遞增的場景。它的實(shí)現(xiàn)比put簡單得多如果當(dāng)前size為0或者傳入的key大于最后一個(gè)key直接追加到數(shù)組末尾不需要二分查找。public void append(int key, E value) { if (mSize ! 0 key mKeys[mSize - 1]) { put(key, value); return; } if (mGarbage mSize mKeys.length) { gc(); } mKeys GrowingArrayUtils.append(mKeys, mSize, key); mValues GrowingArrayUtils.append(mValues, mSize, value); mSize; }這個(gè)優(yōu)化在什么場景下有用比如你從數(shù)據(jù)庫按id升序讀取一批記錄依次放入SparseArray用append就比put快很多因?yàn)槭〉袅嗣看蔚亩植檎摇?. ArrayMap的實(shí)現(xiàn)原理與性能邊界4.1 雙數(shù)組結(jié)構(gòu)的精妙之處ArrayMap的內(nèi)部結(jié)構(gòu)比SparseArray稍微復(fù)雜一點(diǎn)。它有三個(gè)核心數(shù)組int[] mHashes存放每個(gè)key的hashCode升序排列Object[] mArray交替存放key和value即mArray[2i]是keymArray[2i1]是valueint mSize當(dāng)前鍵值對(duì)數(shù)量為什么要把hash單獨(dú)抽出來一個(gè)數(shù)組因?yàn)槎植檎抑恍枰容^int不需要調(diào)用equals。先用hash定位到候選位置再比較key的equals這樣能減少equals的調(diào)用次數(shù)。對(duì)于String這種equals開銷較大的key類型這個(gè)優(yōu)化很有意義。查找流程是這樣的計(jì)算key的hashCode在mHashes中二分查找hash如果找到拿到索引index比較mArray[2*index]和key是否equals如果equals返回mArray[2*index1]如果不equalshash沖突繼續(xù)向兩邊線性探測這個(gè)線性探測是ArrayMap處理hash沖突的方式。因?yàn)閿?shù)據(jù)量小沖突概率低線性探測的實(shí)際開銷可以接受。4.2 緩存機(jī)制與擴(kuò)容策略ArrayMap有一個(gè)靜態(tài)的緩存數(shù)組用于復(fù)用空數(shù)組。當(dāng)你創(chuàng)建一個(gè)新的ArrayMap時(shí)它不會(huì)立即分配數(shù)組而是指向一個(gè)共享的空數(shù)組。只有在第一次put時(shí)才會(huì)真正分配。這個(gè)設(shè)計(jì)在大量創(chuàng)建臨時(shí)Map的場景下能省不少內(nèi)存。擴(kuò)容策略方面ArrayMap的初始容量是4擴(kuò)容時(shí)翻倍。但它的擴(kuò)容有一個(gè)特殊處理如果當(dāng)前容量已經(jīng)很大超過一定閾值會(huì)嘗試收縮。這個(gè)邏輯在trimToSize方法里也有體現(xiàn)。public void trimToSize() { if (mSize mArray.length / 2) { // 收縮數(shù)組 } }實(shí)操心得如果你確定一個(gè)ArrayMap不會(huì)再添加新元素了調(diào)用trimToSize可以釋放多余內(nèi)存。這在緩存場景下很有用比如你把一批數(shù)據(jù)加載進(jìn)ArrayMap后就不再修改trim一下能省不少空間。4.3 與SparseArray的性能對(duì)比同樣是存1000條int到Object的映射SparseArray和ArrayMap的表現(xiàn)有差異內(nèi)存占用SparseArray更低因?yàn)樗恍枰猰Hashes數(shù)組key直接存在int數(shù)組里查找速度SparseArray略快因?yàn)樯僖淮蝖ash計(jì)算和equals調(diào)用插入速度兩者接近都是O(n)的數(shù)組移動(dòng)通用性ArrayMap支持任意key類型SparseArray只支持int所以選型邏輯很清晰key是int就用SparseArray不是int才考慮ArrayMap。不要因?yàn)锳rrayMap更通用就無腦用它。4.4 什么情況下ArrayMap會(huì)翻車ArrayMap不是銀彈以下幾種情況用它反而更慢數(shù)據(jù)量超過1000。二分查找的O(log n)在n1000時(shí)大約是10次比較在n10000時(shí)是14次。雖然增長不快但每次比較都涉及數(shù)組訪問和可能的equals調(diào)用累積起來就明顯了。更重要的是插入時(shí)的數(shù)組移動(dòng)在數(shù)據(jù)量大時(shí)開銷急劇上升。頻繁插入刪除。每次插入都要移動(dòng)數(shù)組每次刪除都要標(biāo)記和可能的壓縮。如果你的場景是不斷增刪的隊(duì)列或緩存ArrayMap的O(n)操作會(huì)成為瓶頸。多線程并發(fā)讀寫。ArrayMap和SparseArray都不是線程安全的。如果在多線程環(huán)境下使用需要自己加鎖而加鎖后的性能可能還不如直接用ConcurrentHashMap。key的hashCode計(jì)算開銷大。ArrayMap每次查找都要計(jì)算key的hashCode。如果key是復(fù)雜對(duì)象且hashCode方法很重這個(gè)開銷會(huì)累積。HashMap也有這個(gè)問題但HashMap的O(1)查找在數(shù)據(jù)量大時(shí)優(yōu)勢明顯。5. 實(shí)際項(xiàng)目中的選型與優(yōu)化實(shí)操5.1 一個(gè)典型的列表緩存場景假設(shè)你在做一個(gè)聊天記錄列表每條消息有一個(gè)自增的long型id你需要根據(jù)id快速找到對(duì)應(yīng)的消息對(duì)象。數(shù)據(jù)量大概幾百條讀多寫少。這個(gè)場景下SparseArray是首選。但注意id是longSparseArray只支持int。如果id范圍在int內(nèi)可以強(qiáng)轉(zhuǎn)如果超過int范圍需要用SparseLongArray或者自己封裝。SparseLongArray的value是longkey是int不滿足需求。這種情況下可以考慮用LongSparseArrayandroidx.collection提供或者用ArrayMapLong, Message。如果消息數(shù)量穩(wěn)定在幾百條ArrayMapLong, Message的表現(xiàn)也不錯(cuò)。但要注意Long的裝箱問題每次put/get都會(huì)創(chuàng)建Long對(duì)象。如果讀寫非常頻繁這個(gè)裝箱開銷不可忽視。一個(gè)優(yōu)化技巧是緩存常用的Long對(duì)象或者用自定義的long key包裝類。5.2 狀態(tài)標(biāo)記場景的SparseIntArray游戲開發(fā)或復(fù)雜UI中經(jīng)常需要維護(hù)大量狀態(tài)標(biāo)記比如每個(gè)技能是否冷卻、每個(gè)格子是否被占用。這種場景用SparseIntArray或SparseBooleanArray非常合適。SparseBooleanArray occupied new SparseBooleanArray(); occupied.put(3, true); occupied.put(7, true); if (occupied.get(3)) { // 處理 }相比HashMapInteger, BooleanSparseBooleanArray省掉了Boolean的裝箱和Entry對(duì)象在格子數(shù)量多的時(shí)候內(nèi)存優(yōu)勢明顯。而且它的get方法有默認(rèn)值重載get(key, false)在key不存在時(shí)返回false比HashMap的get返回null再判空更簡潔。5.3 遍歷時(shí)的正確姿勢SparseArray和ArrayMap都支持通過索引遍歷這比HashMap的Iterator遍歷更高效因?yàn)椴恍枰獎(jiǎng)?chuàng)建Iterator對(duì)象。for (int i 0; i sparseArray.size(); i) { int key sparseArray.keyAt(i); Object value sparseArray.valueAt(i); // 處理 }但要注意如果在遍歷過程中刪除元素size會(huì)變化可能導(dǎo)致越界或漏遍歷。安全的做法是先收集要?jiǎng)h除的key遍歷結(jié)束后再統(tǒng)一刪除?;蛘哂玫剐虮闅vfor (int i sparseArray.size() - 1; i 0; i--) { if (需要?jiǎng)h除) { sparseArray.removeAt(i); } }倒序遍歷在刪除時(shí)不會(huì)影響未遍歷元素的索引是更安全的做法。注意removeAt和delete的區(qū)別在于removeAt直接操作索引不進(jìn)行二分查找。如果你已經(jīng)知道索引用removeAt更快。5.4 性能測試的實(shí)測數(shù)據(jù)我在一個(gè)模擬項(xiàng)目里做過一組對(duì)比測試環(huán)境是Android 10模擬器數(shù)據(jù)量1000條key為0到999的intvalue為String。測試結(jié)果如下數(shù)值為10萬次操作耗時(shí)單位毫秒操作HashMapSparseArrayArrayMapput順序453842put隨機(jī)48120135get命中122832get未命中102530內(nèi)存占用約80KB約40KB約55KB這組數(shù)據(jù)很能說明問題順序插入時(shí)SparseArray和ArrayMap不輸HashMap但隨機(jī)插入時(shí)因?yàn)閿?shù)組移動(dòng)性能下降明顯。查找方面HashMap的O(1)優(yōu)勢在數(shù)據(jù)量大時(shí)體現(xiàn)出來。內(nèi)存方面SparseArray優(yōu)勢最大。所以結(jié)論很明確數(shù)據(jù)量小且插入有序用SparseArray/ArrayMap數(shù)據(jù)量大或插入隨機(jī)用HashMap。這個(gè)“小”的界限根據(jù)實(shí)測經(jīng)驗(yàn)大約在500到1000之間。低于500SparseArray/ArrayMap的綜合表現(xiàn)更好高于1000HashMap更穩(wěn)。5.5 與其它容器的組合使用實(shí)際項(xiàng)目中很少只用一種容器。常見的組合模式是外層用SparseArray做一級(jí)索引內(nèi)層用ArrayMap或HashMap做二級(jí)映射。比如按類型分組的數(shù)據(jù)外層key是類型idint內(nèi)層key是具體名稱String。這種嵌套結(jié)構(gòu)要注意內(nèi)存的累積效應(yīng)。外層100個(gè)類型每個(gè)內(nèi)層100條數(shù)據(jù)總共就是10000條。這時(shí)候內(nèi)層用HashMap可能更合適因?yàn)閱螌訑?shù)據(jù)量雖然不大但總量上去了HashMap的O(1)查找優(yōu)勢會(huì)體現(xiàn)出來。另一個(gè)技巧是用SparseArray存基本類型數(shù)組。比如SparseArrayint[]key是分組idvalue是該組的原始數(shù)據(jù)數(shù)組。這樣比SparseArrayArrayList 省掉了ArrayList的對(duì)象開銷和Integer裝箱。6. 常見問題與排查技巧實(shí)錄6.1 為什么我的SparseArray越用越慢這是最常見的問題。原因通常是插入模式導(dǎo)致的。如果你的key是隨機(jī)分布的每次插入都可能移動(dòng)大量元素。排查方法是打印插入位置的分布如果集中在頭部就要考慮換數(shù)據(jù)結(jié)構(gòu)。另一個(gè)原因是DELETED標(biāo)記積累。頻繁刪除后沒有觸發(fā)gc底層數(shù)組里全是DELETED占位二分查找雖然不受影響但數(shù)組移動(dòng)時(shí)會(huì)帶著這些占位一起移動(dòng)浪費(fèi)CPU。解決辦法是定期調(diào)用gc或者在刪除量達(dá)到一定比例時(shí)重建SparseArray。6.2 ArrayMap的hash沖突怎么排查ArrayMap在hash沖突時(shí)會(huì)線性探測。如果發(fā)現(xiàn)get操作變慢可能是沖突率太高。排查方法是統(tǒng)計(jì)key的hashCode分布看是否有大量key落在相同的hash值上。一個(gè)常見的坑是用自定義對(duì)象做key但沒有正確實(shí)現(xiàn)hashCode。如果所有對(duì)象的hashCode都返回同一個(gè)值A(chǔ)rrayMap就退化成線性查找性能比ArrayList還差。確保key的hashCode方法遵循標(biāo)準(zhǔn)約定相等的對(duì)象必須有相同的hashCode不相等的對(duì)象盡量有不同的hashCode。6.3 遍歷時(shí)ConcurrentModificationExceptionSparseArray和ArrayMap不像HashMap那樣有modCount檢查所以遍歷時(shí)修改不會(huì)拋ConcurrentModificationException但會(huì)導(dǎo)致不可預(yù)期的結(jié)果。比如你正序遍歷時(shí)刪除了一個(gè)元素后面的元素會(huì)前移導(dǎo)致下一個(gè)元素被跳過。這個(gè)問題的隱蔽性在于它不報(bào)錯(cuò)只是結(jié)果不對(duì)。排查方法是檢查遍歷過程中是否有修改操作。如果有改用倒序遍歷或先收集再處理。6.4 內(nèi)存泄漏的隱蔽來源SparseArray和ArrayMap本身不會(huì)導(dǎo)致內(nèi)存泄漏但如果value持有Context或View的引用而Map的生命周期比它們長就會(huì)泄漏。常見場景是把Map作為靜態(tài)緩存value里存了Activity的引用。排查方法和普通內(nèi)存泄漏一樣用LeakCanary或Profiler抓堆轉(zhuǎn)儲(chǔ)看Map的引用鏈。解決辦法是用WeakReference包裝value或者在合適的生命周期回調(diào)里清空Map。6.5 常見問題速查表問題現(xiàn)象可能原因排查方法解決方案插入變慢key隨機(jī)分布數(shù)組移動(dòng)多打印插入位置換HashMap或調(diào)整key設(shè)計(jì)查找變慢hash沖突多或數(shù)據(jù)量大統(tǒng)計(jì)hash分布優(yōu)化hashCode或換容器遍歷結(jié)果不對(duì)遍歷時(shí)修改了容器檢查遍歷中的修改操作倒序遍歷或先收集后處理內(nèi)存占用高DELETED標(biāo)記積累查看底層數(shù)組長度定期gc或重建內(nèi)存泄漏value持有長生命周期引用堆轉(zhuǎn)儲(chǔ)分析引用鏈WeakReference或及時(shí)清空實(shí)操心得不要憑感覺判斷性能問題。Android Studio的Profiler可以看內(nèi)存分配和CPU耗時(shí)Systrace可以看主線程卡頓。先測量再優(yōu)化最后驗(yàn)證。我見過太多人憑直覺把HashMap換成SparseArray結(jié)果因?yàn)閿?shù)據(jù)量太大反而更慢。6.6 一個(gè)容易忽略的細(xì)節(jié)初始容量SparseArray和ArrayMap都支持預(yù)設(shè)容量。如果你知道大概要存多少條數(shù)據(jù)提前設(shè)置容量可以避免多次擴(kuò)容。SparseArrayObject array new SparseArray(100); ArrayMapString, Object map new ArrayMap(100);但要注意預(yù)設(shè)容量太大會(huì)浪費(fèi)內(nèi)存。SparseArray的擴(kuò)容策略比較保守預(yù)設(shè)一個(gè)略大于實(shí)際需求的容量是合理的。ArrayMap的初始容量是4如果你要存50條預(yù)設(shè)64比讓它從4擴(kuò)到64要快。這個(gè)優(yōu)化在循環(huán)創(chuàng)建Map的場景下效果明顯。比如在Adapter的getView里創(chuàng)建臨時(shí)Map預(yù)設(shè)容量能減少擴(kuò)容次數(shù)降低GC頻率。7. 從源碼看設(shè)計(jì)模式與擴(kuò)展思路7.1 GrowingArrayUtils的復(fù)用設(shè)計(jì)SparseArray和ArrayMap的擴(kuò)容邏輯都委托給了GrowingArrayUtils這個(gè)工具類。它提供了append和grow兩個(gè)方法分別處理追加和擴(kuò)容。這種把通用邏輯抽出來的做法值得學(xué)習(xí)。如果你要自己實(shí)現(xiàn)一個(gè)類似的有序容器可以直接復(fù)用這個(gè)思路把數(shù)組增長、元素插入這些通用操作封裝成靜態(tài)方法容器類只負(fù)責(zé)業(yè)務(wù)邏輯。這樣代碼更清晰也更容易測試。7.2 容器類的線程安全替代方案SparseArray和ArrayMap都不是線程安全的。如果需要在多線程環(huán)境下使用有幾種方案用synchronized包裹所有操作簡單但性能差用ReentrantReadWriteLock讀多寫少時(shí)性能更好用ConcurrentHashMap替代但失去了內(nèi)存優(yōu)勢用ThreadLocal為每個(gè)線程維護(hù)獨(dú)立副本適合讀多寫極少且數(shù)據(jù)可容忍不一致的場景選擇哪種方案取決于你的并發(fā)模式。如果只是偶爾的并發(fā)讀加讀寫鎖就夠了。如果寫操作也很頻繁ConcurrentHashMap是更穩(wěn)妥的選擇。7.3 自定義容器的擴(kuò)展方向理解了SparseArray和ArrayMap的原理后你可以根據(jù)特定需求做擴(kuò)展。比如固定容量的SparseArray避免擴(kuò)容開銷帶LRU淘汰的ArrayMap用于緩存場景支持批量操作的SparseArray減少數(shù)組移動(dòng)次數(shù)帶版本號(hào)的ArrayMap用于快照和回滾這些擴(kuò)展的核心思路都是一樣的在有序數(shù)組的基礎(chǔ)上根據(jù)具體場景調(diào)整插入、刪除、查找的策略。沒有萬能的數(shù)據(jù)結(jié)構(gòu)只有適合特定場景的數(shù)據(jù)結(jié)構(gòu)。7.4 從Android到通用Java的遷移ArrayMap在androidx.collection包里可以脫離Android環(huán)境使用。如果你的Java項(xiàng)目有類似的需求——小數(shù)據(jù)量、讀多寫少、內(nèi)存敏感——完全可以引入這個(gè)依賴。但要注意androidx.collection的ArrayMap和Android框架里的ArrayMap在API上略有差異??蚣馨嬗幸恍〢ndroid特有的優(yōu)化androidx版更通用。遷移時(shí)注意檢查方法簽名和返回值。8. 一些踩過的坑和最后的建議先說一個(gè)我踩過的坑。有一次在一個(gè)列表頁里用SparseArray存Item的狀態(tài)key是position。列表支持拖拽排序每次拖拽后position會(huì)大量變化導(dǎo)致SparseArray里頻繁插入刪除。結(jié)果滑動(dòng)時(shí)明顯卡頓Profiler一看CPU時(shí)間全花在System.arraycopy上。后來換成HashMap問題立刻消失。這個(gè)教訓(xùn)是position這種會(huì)頻繁變動(dòng)的值不適合做SparseArray的key。另一個(gè)坑是關(guān)于DELETED標(biāo)記的。有一次我在遍歷SparseArray時(shí)刪除元素用的是正序遍歷加remove。代碼邏輯看起來沒問題但測試發(fā)現(xiàn)偶爾會(huì)漏掉一些元素。排查了很久才意識(shí)到是DELETED標(biāo)記和數(shù)組移動(dòng)的交互導(dǎo)致的。改成倒序遍歷后問題解決。還有一個(gè)關(guān)于ArrayMap的坑。我用ArrayMapString, Bitmap做圖片緩存key是圖片URL。后來發(fā)現(xiàn)內(nèi)存占用比預(yù)期高很多。原因是ArrayMap的mHashes數(shù)組和mArray數(shù)組都會(huì)隨著數(shù)據(jù)量增長而擴(kuò)容而且不會(huì)自動(dòng)收縮。調(diào)用trimToSize后內(nèi)存降下來了。所以如果你用ArrayMap做緩存記得在數(shù)據(jù)穩(wěn)定后trim一下。最后給幾條實(shí)用建議數(shù)據(jù)量小于500且key是int無腦用SparseArraykey不是int但數(shù)據(jù)量小用ArrayMap數(shù)據(jù)量大于1000或插入頻繁用HashMap遍歷時(shí)刪除用倒序或者先收集后處理預(yù)設(shè)容量能省擴(kuò)容開銷但別設(shè)太大定期trim或gc避免數(shù)組膨脹多線程場景加鎖或換ConcurrentHashMap性能問題先測量再優(yōu)化別憑直覺這些經(jīng)驗(yàn)都是從實(shí)際項(xiàng)目里一點(diǎn)點(diǎn)攢出來的希望能幫你少走些彎路。數(shù)據(jù)結(jié)構(gòu)和算法的選擇從來不是非黑即白理解每種結(jié)構(gòu)的取舍根據(jù)具體場景做判斷才是工程師該做的事。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
中文欧丝袜诱惑| 欧美色图亚洲色图成人在在线| 97色涩| 日韩激情毛片一级久久久| 免费亚洲国产精品久久一区| 五月天婷婷久久| 懂色Av一区二区三区| 人人人人人人少妇| 国内毛片国产专区二| 日韩青久久| 极品色社| 亚州操逼网| 精品久久久久久AV无码| 亚洲色欧美| 国产精品久久久久999| A V视频日本| 天美久久久久| a人欧美综合天堂麻豆| 色婷婷电影| 日本成a人v网站在线观看| 97这里只精品| 福利风月五月天影院| 色综合尤物| 色视频蜜乳| 婷婷探花久久精品一区| 狠狠爱AV| 白 大 人妻 区 在线| 91中文在线| 国产欧美日本亚洲精品| 强奸乱伦AV网站| 97资源久久| 福利五区| 美女久久久| 东京热av影院| 老熟女乱伦片| 午夜操一操| 亚洲无码一区成人免费午夜| 国产精品午夜精品| 精品无码一区二区| 黄网站黄视频网站进入口| 91网站18在线| 绑缚麻绳人妻寝取完整版| 天天淫人人妻日日色| 偷窥自拍亚洲天堂网爆| 国产精品免费视频不卡| 国产伦乱91| 在线看片国产精品每日更新| 色翁荡息又大又硬又粗又爽| 上特色A在线| 久久99久久99精品天美传媒棢·纸:.| 色悠久久久av| 天天干夜夜操一区二区| 99热这里都是精品| 丝袜亚洲综合| yw尤物av无码点击进入麻豆| 欧美一区二区三区成人性生活| 丝袜大香蕉| 1024人妻熟女一区二区三区| 操逼啊啊啊91| 免费在线观看AV无码网站| 精品国产久热在线观看| 九九aV| 色操逼网| 日韩一级特黄av毛片| 国产毛片久久久久久久| 97人人操人人摸人人爱| 婷婷激情五月天小说网| 日韩欧美国产高清视频| 久久久久久亚洲中文| 最新日日夜夜天天干干| 99re在线观看| 中文高清一区二区的| 任我爽在线视频免费观看| 国产成人欧美精品在线| 探花熟女,姿勢到位,體驗感也到位| 日本肏逼视频在线观看| 色淫网站优优视频| 91丨国产丨白浆| 日本不卡二区| 另类视频在线| 九九久久99| 九九九九九九九九九九九九九九九女| 亚洲成?V人片在线观看福利| 国产高清成人免费视频| 国产精品电| 久久激情视频| 色久桃花影院在线观看| 九九九成人| 有码免费观看| 五月激情啪啪| 欧美视频在线视频免费va| 精品久久久久综合无码| 超碰久久精品| 久久欧洲| 亚洲老熟妇xxx| 新久久AV| AV一区观看| 亚洲色图综合| 色约约一区=区三区| 超碰在线97国产| 国产乱码久久| 欧美人妻精品| 国产第二页| 成人综合网 欧美| 成人熟女视频一区二区三区| 欧美亚洲涩涩| 天天内射| 亚洲男人天堂手机版| 色爱天堂| 强奸乱伦 亚洲一区| 日韩在线欧美精品一区二区| 九九热最新| 黑丝自慰喷水网站| 九九九九久久久| 亚洲熟久久| 91高清日| 999亚洲国产视频| 九九热精品| 久久精品免费| 久久婷婷苹果| 熟妇操花| 欧美性五月| 免费岛国一级片| 成人免费福利在线观看| 91天天综合网,天天综合网| 国产精品丝袜在线| 99久久精品无码一区二区| 成人无码在线超碰网| 国产精品无码AV网站| 吉川爱美98堂在线| 欧美九九九九九| 国产欧美岛国精品一区| 日韩欧美偷拍美女视频| 麻豆尤物视频网| 国产成人精品必看 | 久久99久久99精品免视看婷婷| 久艹视频在线| 欧洲色| 综合97| 人夜夜精品网站香蕉嫩草| 天美麻豆精品视频99| 夜夜操一区二区| 97亚洲中文| 久久久亚洲高清不打码| 91蜜桃传媒精品久久久一区二区| 强奸乱伦AV一天堂网| 人妻-91porn| 久久久久久91香蕉国产| 欧美丝袜91| 国产一区二区a毛片| 中文字幕在线观看AV| 亚洲精品蜜桃久久久| 涩涩涩综合| 亚洲欧洲视频小说在线观看| 日本高清加勒比| 国产成人亚洲精品无| 日本精品中文字幕视频| 麻豆 亚洲 97| 日韩中文字幕二区| 91色婷婷综合久久中文字幕二区| av天天在线观看| 亚洲九九视频| 亚洲欧美爆| 精品久久久久久AV无码| 男人的天堂久久狠| 日本综合久久| 9999免费精彩视频| 人人妻人人狠人人| 嗯嗯啊啊操我| 91色伦| 久久久99久9| 综合亚州欧美| 亚洲欧美日韩国产丝袜自拍中文| 日本一区二区成人在线| 97超碰人人模人人拍人人| 玖玖爱一区在线| 白天啪啪晚上啪啪视频| 国产中文日韩欧美一区二区三区人妻丝袜美腿| 69精品人人人人| 逼逼逼逼操操操操操操操操操午夜剧场 | 囯戸精品高潮呻吟旡码| 欧亚无码视频| 亚洲 小说 欧美 激情 另类| 欧洲在线性爱视频| 在线αⅴ| 熟女乱伦A| 婷婷去俺也去六月色| 99re国产精品视频| 天天插天天射| 老师充足的奶水小说| 美女大乳久久久久久久女人18| 日本精品成人无码| 妇女性内射冈站HDWWWCOM| 欧美线天码中字| 人人超碰在线观看黄| 人人插人人搞人人操| 欧美中文字幕日韩在线| 国产乱色国产精品免费视| 精品无码一区二区三区| 在线岛| 日本性爱不卡视频| 日韩午夜精品一区二区三区电影| 99久热| 色女网日韩| 97视频新免费| 亚洲精品人妻在线| 97日亚洲欧美| 免费家庭乱伦视频| 欧美精品自慰系列寂寞少妇 | 在线国产探花| 欧美久久毛片基地| 久久久久熟女| 人妻日日干| 一区二区三区四区姦女| 91麻豆天美| 成人午夜视频免费播放| 久久精品无码不卡| 成人av影院在线观看| 国产亚洲综合欧美一区| 亚洲人在线成线成人| 91精品国产91熟女| 中文字幕一区日韩精| 天天日美女的B| 色y情视频免费看| 精品久久久久久亚洲| 欧美熟妇精品黑人巨大91| 91成人在线免费视频| 亚洲国成人情色好看电影| 丁香九月婷婷| 天天舔九色婷婷| 第四色奇米影视777| 99色日| 国产91啪| 欧美性夜| 亚洲三级网址久久最新| 国产女人高潮嗷嗷嗷叫小说 | 久久最新免费视频23| 热99这里有精品综合久久 | 东北老熟女| 99综合免费视频| 成人区人妻精品一| 国产suv精品一区二区四区999 | 日本免费一区二区不卡| 天美国产精品| 国产尤物AV尤物在线观看不卡| 亚洲女人91| 麻豆黄四叶草网站| 伊人五月天| 精品久久97| 91黑丝少妇| 精品国产人成在线| 精品美女少妇一区二区| 欧亚第一综合网| 国产粉嫩出水在线播放| 欧亚日韩中文在线| 国产夫妻性生活视频| 欧美日韩性感| 欧美日韩一区二区三区四区蜜桃| 91观看 国产白丝| 日韩 人妻 精品| 亚州人妻| 国产久久久9999| 男人a天堂手机在线版| 亚洲国产97| 欧美夜色| 啊啊啊快操我视频| 91l欧美在线| 欧美一区二区在线资源| 欧美91变态| 欧美日韩97在线| 黑丝91视频| 欧美福利视频啊啊啊啊| 国产日韩美女小穴视频网站不卡| 内射中出日韩在线观看视频| 97 亚洲 日韩 欧美 在线| 日本视频一区二区三区| 牛牛AV人人夜夜澡人人爽| 91少妇香蕉久久精品| 日本九九久久99播| 美女诱惑1区2区| 婷婷综合视频| 国产女人高潮视频| 天天摸夜夜摸| 乱老熟女一区二区三区| 97天天在线| 蜜桃网熟妇| 欧美亚洲首页| av毛片aaaaa免费看| 东京热一区二区中文字幕| 欧美激情专区| 亚洲欧洲综合av在线| 久久香蕉综合一本到3atv| 思思在线免费视频| 国产高潮AA片免费看| 免费啪啪啪网站18岁| 国产传媒1234区| 青草香蕉网| 久久视频,这里只有精品 | 夜夜操av亚洲一区二区| 无码九九| 手机在线免费看的av| 欧美综合区| 又摸又舔在线观看网站| 色激情综合网站| 国产福利第一视频| 亚洲AV色图一区| 亚洲伊人久久综合97| 嗯啊抽插大香蕉网页| www.黄色在线| 裸体美女免费看网站青草| 欧美亚洲20p| 欧美精品系列| 综合操逼| 亚洲青青草| 欧州一区二区三区四区| 九九色精品| 性生活久久久久久久久久| 操逼无毒无码免费视频| 综合影院永久入口国产| 色色99| 麻豆熟妇乱妇熟色A片在线看| 日本1区2区不卡视频| 嗯嗯嗯啊啊啊在线免费观看| 999热日韩精品| 啪啪视频亚洲第一| 亚洲视频,小说| 综合久久久久久久久91| 嗯嗯啊啊日韩精品| 玖草在线视频| 久久精品天美| 狠狠操夜夜| 96免费视频在线| 日韩免费中文字幕视频| 亚射在线| 欧美久久人人网| 97色视频在线| 婷婷中文字幕| 亚洲无码一二三区| 好属操| 91neishe| 为用户提供免费看黄网址在线观看| 中文字暮97| 97天天摸天天爽| 亚洲国产综合久久久性感熟妇| 久久久久久九九九九| 97内射偷拍| 在线观看黄色电话| 91一区二区三区蜜桃| 亚洲欧美精品久| 久久免费精品视频免一| 97超碰色色| 国产青视频| 日韩性爱电影一区| 97日韩欧美| 天美一二三在线观看Av| 久久草大香蕉| 久久毛卡| 无码天天操| 欧美福利视频啊啊啊啊| 射综合网| 啊啊啊啊免费视频| 综合亚洲欧美| 日韩91网站| 人妻天天爽| 亚洲自拍另类丝袜综合| 天天综合网~69| 亚洲无线码一区国产欧美国| 国产免a费看黄片在线| 久久久精品久久| 午夜呻吟欧美| 国产丰满熟夫69mpp| 欧美v日韩欧亚洲电影天堂色诱,国产传媒| 亚洲欧洲网站免费观看| 综合色99| 激情网五月天| 亚洲人成网www| 高清在线偷拍自拍视频| 久久曰曰| 久久麻豆一区二区| 玖玖视频在线资源一区二区三区| 男人的天堂亚洲| 五月天激情国产综合婷婷婷| 91最新综合| 综合亚洲情色| 日本一级不卡一二区| 一二区在线观看视频| 亚洲天堂精品日韩电影| 最新日日夜夜天天干干| 91久久九九精品国产综合| 亚洲一区日韩精品中文字幕| 免费自拍三级综合| 国语av最新自产拍在线观看| 国产精品成人蜜臀AV在线| 久久精品国产免费观看99| 人人看人人摸人人色| 五月天婷婷综合| 人人妻人人色| 国产97视频| 台湾成人无码AV| 男人的天堂亚洲| 东京热不卡视频| 欧美极品美女aaaaaa级黄片| 大香蕉伊人久久| 高潮嗯啊性感美女久久久| 久久激情四射婷婷丁香五月天| 天天躁日日躁狠狠躁| 久久这里只| 亚洲自拍天堂| 歐美一級亂黃99在綫精品| 超碰97亚洲区| Sekablack无码一区| 五月天春色激情网| 欧美色图 色综合图| 首页中文字幕中文字幕免费| 欧美成人综合| 26UUU欧美日本| 日韩另类| 熟女熟妇一区二区三四区| 国产精品亚洲一区二区三区四区| 天天爱综合网| 大香蕉九九| 日韩图色| 乱理日韩中文| 亚洲性爱电影| 日韩中文字幕2020| 精品亚洲国产成人AV制服丝袜| 亚洲男人综合网| 黄片色区软件| 亚洲欧洲激情| 国产精品电影| 国产成人91一区二区三区| 偷拍 精品另类 凸凹了四区| 日韩熟女三十乱伦| 清清草影| av大香蕉| 日本人妻中文字幕精品| 亚洲在线观看| 精品人妻一区二区三区-国产精品| 1769成人国产精品视频| 日欧毛片久久| 富二代亚洲精品99| 极品内射| 狠狠干,狠狠操| 国产Av超碰| 99re视频在线播放青草| 国模精品娜娜一二三区| 97超碰9| 久久天天躁日日躁狠狠躁| 新婚人妻扶着粗大强行坐下| 香蕉精品二区二区| 新精精品久久精品| 超碰国产情侣自拍网| wwwcaobibi| 乱伦一二三区| 亚洲色图欧美| 4tube欧美女厕所| 91久久久视| 99性爱| 丰满人妻无码一区二区三区| 午夜福利1区2区3区| 91久久| 国产成人五月天丁香花| 97久久精品不卡| 亚州中文字幕超碰97| 久久国产99精品72福利| 免费啪啪啪网站18岁| 日本成a人v网站在线观看| 超碰色大香蕉| 欧日韩一二三f区| 一区二区三区男人的天堂| 成人在线午夜视频一区| 久操在97| 爱丝福利| 中国熟妇| 翔田千里AV无码秘 三区| 精品国产乱码久久久久久网站入口| 天天欧美97| 天天干嫩逼网| 九九综合久久中文字幕| 睡产熟女乱伦| 久久精彩视频9| 97 九色| 91熟女视频网| 97精品| 欧美国产精品久久九九| 欧美亚洲| 亚洲图片 91| 91天射| 999九九九九国产动| 欧美色图欧美| 伊人精品久久网站| 98色网| 亚洲资源网| 色婷婷一区二区三区久久| 熟妇的味道HD中文字幕| 欧美视频在线视频免费va| 800zy一区二区| 人干人人人操人人摸| 精品超碰中文在线| 高潮9999外国| 精品免费视频国产一区| 亚洲天堂无码| 天天插夜夜爽| 亚洲一二三四区| 人人操人人摸人| 中文字幕视频2区| 超碰吊日色| 少妇啪啪自拍| 青青草吊丝| 亚洲色图A| 亚欧性爱ab| 抽插爽| 久久久久久网址| 中文字幕二区| 天天噜| 午夜福利精品| 欧美亚洲涩涩| 无码WWW免费视频网站| 亚州精品丝袜-不卡成人免费| 91欧美亚洲| 一区二区偷拍拍视频| 精品夜夜澡人妻无码AV| 九九人人操| 怡春院久久| 五月婷婷丁香| 无码操逼网| 夜夜操一区二区| 五月丁香啪啪网| 狠狠干91| 中文字幕伊人| 九九综合久久| aa片毛片| 人妻黑丝袜电影| 欧美日韩国产色图在线| 偷拍 亚洲 欧美| 天美传媒AV国产在线| 亚洲黄网在哪免费看| 亚洲在饯| 智利AV在线网| 国产av白丝| 国产精品激情久久久久久久| 欧美亚洲91| 亚洲精品97中文字幕| 日韩精品 资源| 久干9操| 日本精品999| 四虎在线免费视频| 插老姨肥穴| 91一区二区| av凤凰久久久| 中文字幕乱在线伦视频中文字幕乱码在线| 五月天人妻综合| 东京热精品97综合网| 男人的天堂2019AV| 国产又粗又长又爽又色| 国产亚洲福利第一页丝袜| 亚洲美女 晚间男人天堂| 久热大香蕉| av在线不卡一区二区三区| 日韩精品三级| 97精品一区| 吊色| 在线电影亚洲色图| 中文字幕欧洲有码| 丝袜美腿操av| 91亚洲网站| 暴力av在线| 97操| 91精品老女人| 成人小说另类在线| 26uuu性物| 人、人、摸,人、人、草| 污污汅18禁网站在线永久免费观看| 91性高朝久久久久久久久| 天天日天天干天天操| 久久成人东京热人妻| 大香蕉99热| 91肏屄网| 色五月婷婷五月天| 男人的天堂网免费| 97超碰国产精品| 日韩精品人妻系列无码天堂| 国产视频第2页| 欧美色图另类图片| 被男人添B超爽视频| 亚洲精品第一| www.一本大99| 超碰97久| 精品亚洲国产成人av网站| 国产精品亚洲免费| 久久婷婷国产一区二区色| 99re6久热只有精品6在线直播| 人人操天天爽| 日韩97超碰| 99久久精品无码一区二区毛片免费| 蜜乳av一区二区| 天天爽天天操| 97视频免费在线| 天天干美少妇一区| 国产中午字一暮区| 性饥渴少妇av无码毛片| 在线黄页看毛片| avav青青草久久夜| 丰满人妻无码一区二区三区| 99热亚洲天堂| 欧美激情 一区| 亚洲91在线播放影院| 美女黄色一级A视频| 操死我了啊啊啊| 国产后入精品| 中文熟女五十乱码在线| 琪琪精品免费一区二区三区| 国产传媒日本欧美专区| 96精品久久久久久久久久| 发朗少妇买婬全视频中文| 久久人妻无码毛片A片麻豆| 国产熟女精品一区二区| 九月婷婷久久| 一起草视频在线| 亚洲va综合va国产va中文| 91n处女在线观看| 午夜免费视频1000| 免费人成毛片乱码| 亚州色图欧美| 久久伊人五月天| 狠狠婷婷亚洲中文综合久久| 日韩国产十八禁| 韩国成人精品久久久免费看| 天天干天天日天天射黄色片| 九九精品99| 综合大香蕉美。| 在线另类| 国产人妖的免费的视频| 色婷婷日韩精品一区二区三区| 丁香五月激情综合国产| 国产精品熟女一区二区三区| 欧美亚洲AN| 99无码视频| 中文字幕一区二区日韩网| 校园春色美腿丝袜| 伊人青青一区成人视频在线观看区| 婷婷色综合欧美日韩| 国产精品电影推荐| 91国产精品在线看| 天天操天天射天天日| 久久青青草在线视频| 成人A片男人的天堂| 色啪网| 飘花国产午夜精品不卡| 少妇大屁屁| 2017超碰| 91超碰碰在线| 大香蕉 222| 丁香五月影院| 亚洲、日韩、综合、另类| 色婷婷六月丁香七月婷婷| 操人妻视频| 熟女人妻一区二区三区| 90后后入| 老熟女综合网| 97视频在线播放| 欧美一级二级三级| 69久久| 人妻色情天天操| 超碰97在线中文| 98精品国产乱码久久久久久| 夜夜夜久久| 色香阁在线| 国产精品久久久视频| 国产伦乱91| 最近的最新的中文字幕视频| 国产女性无套 免费观看| 激情专区综合| 内射日韩大臀美女| 嗯嗯啊啊视频一区二区三区| 日日夜夜国产综合| 乱老熟女一区二区三区| 99re95| 伊人亚洲综合| 精品人妻一区二区三区四区| 伊人天天久久动态图| 久久欲| 亚洲最大网站av| 伊人AAA| baiduhicn.com。| 亚洲图片激情小说| 老熟妇一区二区三区…| 精品亚洲黄色片 国产精品导航一区二区 | 国产大学生高潮在线播放| 色五月首页| 北条麻妃99精品青青久久| 91黑丝美女| 日日爽熟女| 国产最新小视频在线播放下载| 久久亚洲精品成人av| 手机在线观看不卡无码av| 久久露脸国产老熟女| 久久大香蕉手机高清| 东北老女人的激情视频| 9ⅰ久久久天天| 五月天婷婷在线看| AV色天香在线| 欧美精品激情| 国产又操| 国产欧美日产一区二区三区 - 国产欧美日| 国产精品操| 欧美一区二区三区日韩| 欧美国产有色电影| 精品无码久久久久久久杏吧| 亚洲日韩精品在线播放| 欧美猛交黑寡妇中文字幕| 精品对白久久不卡| 午夜大香蕉| 91热热色| 激情五月婷婷| 99久久久| 色婷婷丁香五月| 91亚洲网站| 日韩91网| 亚洲国产精品乱码在线观看| 日韩一卡二卡三卡| 91五月天| 欧美色图亚洲色| 东北女人av| ji熟女.com| 99精品丰满人妻无码| 亚洲免费人妻在| 国产三级片在线观看| 人妻在线臀日韩| 又大又大又大又粗爽高潮观看| 91亚·色| 一二三四视频中文字幕在线看| 大香伊人在线一区| 熟女视频久久| 富女玩鸭子一级毛片| 久久99精品九九久久久婷婷| 91丨熟女丨丰满熟女| 懂色av中文字幕| 天天摸天天插天天日| 乱伦av麻豆| 91精品老女人| 变态另类专区| 日本A级视频| 一区三区啪啪| 男女做爰猛烈动高潮A片免费应用| 亚洲在钱| 亚洲怡春院| 嗯……啊…嗯嗯…啊…好舒服| 999亚洲国产视频| 久久久久久久97| 一区二区三区在线日韩影院观看| 99.色网| 国产色呦呦| 男人的天堂com| 91红杏| 婷婷综合| 2021久久国产综合精品青草| 九九九九精品精| 一牛一区二区三区久久| 久久久久9999| 欧美aa一级片| 精品一区二区三区国产| 超碰诱惑| 91人妻在线视频| 日韩肏逼视频| 国产无码精品高清| 亚洲九九九| 果冻传媒A片麻豆熟妇人妻| 人妻五十路在线| 天美传媒Av在线| 歐美性天天| 新精精品久久精品| 最新中文字幕精品在线| a级成人毛片免费视频高清| 国产福利一区二| 欧美一级在线观看成人| 伊人国产成人av网站| 男女啪啪啪18禁网站| 久久透逼视频| 综合久久中文字幕综合日韩精品| 操一区| 情色av电影| 国产精品久久久九九九| 亚洲骚男同com| 97视频免费| 欧美高清第一页| 亚洲熟女综合一区二区| 国产免费小视频| 国产农村妇女精品| 日韩午夜精品一区二区三区电影| 人妻-91porn| 久久五月份| 亚洲男人的天堂网| 黄色无码高清黄色无码网站| 最新av中文字幕高清| 91操操| 夜夜精品视频一区二区| 熟女探花啪啪| 乱伦日本色图AⅤ| 99热超碰| 亚洲无 码A片在线观看麻豆| 国产一区二区在线电影| 欧美综合 站| 久久性爱视频99| 国产亚洲人妻综合日韩 久久| 青久操| 啊啊啊草死我| www.色婷婷| 欧美女同在线| 亚洲一区二区性爱电影| 国产乱人妻精品入口| 国产中文大片资源中文字幕| 97舔舔| 啊啊啊好想要| 成年男人的天堂| 亚洲精品国语在线播放| 精品然女一区二区| 中文色综合| 91九九九小逼| 免费观看性欧美一级| 日本A级视频| 国产亚洲日韩在线三区黑人| 97在线观视频免费观看| 亚洲一区二区性爱电影| 色亚洲欧美| 99热综合| 男人的午夜天堂| 台湾佬中文娱乐自偷自拍| 国产婷婷综合在线观看| 老鸭窝黄色视频网站| 99久在线精品99re8| 中欧人妻丝袜中文字幕| 69综合网| 久久香蕉综合一本到3atv| 日本精品加勒比海一区| 久久婷婷色综合一区二区三区| 天天懆天天日| 亚洲九九九九| 内射中国少妇高清视频免费视频| 熟女人妇一区二区三区| 蜜臀网 一区| 久久一二三四不卡 | 日本天天色| 老熟妇一区二区三区…| 又大又大又大又粗爽高潮观看| 免费97视频| 久久久国产亚洲精品系列| 天天干夜夜操一区二区| 粉嫩国产精品久久久| ′ !γ}丶。。久久精品欧美一区二区三区 | 九九热最新| 好看的91视频| 亚洲性天堂| 天天日夜夜| 大奶的诱惑| 婷婷五月天影院| 久操影视| 欧美人人AAA| 黄站在线免费观看| 3p国产色噜噜一区| 欧美日韩制服| 欧美一级色| 97AV在线观看| 91久久18禁| 人人操人人插人www| 欧美大片天天看| 男女性感激情网站| 蜜臀th| 亚洲第一精品在线视频| 欧美78| 人人操人人摸人| 插插综合网天天影视网| 亚洲AV免费在线| 亚洲天天更新| 夜夜騷av、一區二區| 双插性欧美一二三区| 色婷婷淫色网| 日韩欧美经典在线观看| 亚洲中文字幕av| 97色诱| 秋霞蝌科网日本一区| 后入式999| 欧美日韩丝袜 | 级做a爱无码性色永久免费| 人人乐大香蕉| 中国zzijzzijzzwww精品| 国产91专区| 欧美|91色综合| 日韩免费高清大片在线| 青青欧美| www.zbzhongsen.com| 啊啊啊想要| 日本新免费二区三区| 日韩精品一区二区三区色欲| 欧美亚洲综合高清在线| 欧美色图 人妻| 天美传媒av 在线| 女人被男人桶爽视频网站| 欧美激情亚洲情色| 超碰国产情侣自拍网| 国产女人和拘做爰视频| 超碰在线一区二区| 国产一区二区三区,在线观看观看| 日韩AV熟女乱伦| 亚洲一级黄色毛片| 日日干夜夜骑| 日产狠狠干| 立川理惠无码一区二区| 一区二区乱码福利| 欧美97日韩精品| 97色伦欧美| 日韩探花精品在线视频| 啊啊啊啊啊啊好多水| 亚洲精品国产熟女久久久| 六月丁香五月婷婷| 欧亚成人| 日韩强奸av| 国产精品一区二区三区免费视频| 天堂在线一区二区| 欧美黄色大香蕉一区二区| se01国产在线视频| 国产一级内射高清视频| 亚洲双插| 色天堂在线观看| 欧美色66| 91色综合激情| 欧洲无码一区二区| 日韩卡一卡二卡三在线| 富女玩鸭子一级毛片| 蜜臀99精品国产高清在线观看| 五十路人妻在线| 亚洲情色在线| 看日韩美女二区三区免费操逼视频 | 性色av婷婷久久一区二区点复制| 69一区二区三区| 亚洲人妻精品一区二区| 中文字幕日韩情色| 欧美婷婷久久| 国产自产91区13区| 午夜激情床戏激情| 欧美制服另类丝袜| 嗯啊不要在线观看嗯啊| 久久XX| 一级黄色视频网| 日韩欧无码一区二区三区免费不卡| 99少妇| 亚洲男人在线观看天堂| 又黄又硬又粗又长国产视频| 天堂精品| 亚洲和欧美裸体美女双飞视频| 91色噜噜狠狠| 激情图片伦理国产一区二区日韩| 狠狠操狠狠燥| 日韩情色AV| 91精品久久久久久久久久| 97日视频| 天堂资源站| 97频视在线| 人妻另类| 欧美激情在线观看视频| 超碰九7| 亚洲国产成人综合碰碰三级经典| 天天射天天操天天干天天吃2018 | 少妇精品久久| 狠狠91| 日韩天天综合| 久久精品人妻一区| 成人av毛片在线观看| 在线毛片片免费观看| 日本免费一级AAA大片器| 久久久国产亚洲精品系列| 国语av最新自产拍在线观看| 黑人无码一区二区| 91狠狠综合久久久久久| 99久久无色码| 1二区9| 丝袜色综合| 99re视频在线播放青草| 亚洲天堂2020| 香蕉欧美| 韩国一级婬片A片无码天美| 加勒比久久综合网高清| 欧美日韩操逼嗦吊| 夜夜嗨AV一区天天| 在线综合 亚洲 欧美中文字幕 | 九一国产精品| 欧美另类丝袜熟女| 欧美精品庄| 中文字幕AV乱伦| 成视频在线观看免费看| 97超碰国产精品| 亚洲Av噜噜一区二区三区妖精| 天天香香欲综合| 国桃视频产巨乳精品一区二区在线| 另类欧美色| 在线播放免费av福利片| 国产精品久久久久久久久AV大片| 精品少妇一区二区三区免费观看| 嗯嗯啊操我| 亚洲极品| 激情综合网激情综合| 黑人无码一区二区| 久久9 9 9精品| av2014 日韩在线中文字幕| 热思思免费视频| 99久久网站| 亚洲精品国产精品乱码不卡| 91n欧美| 三级特黄60分钟播放| 碰碰在线视频| 物业黑人 AV一区| 在线中文字幕| 激情文学网伊人| 欧洲大香蕉| 色欲久久99国产精品久久久久久| 美女操逼福利视频| 国产日韩精品一区二区三区| 色777999综合| av在线播放国产一区| 啊a一区在线| 女人香蕉久久毛毛片精品| 成 人片 黄色大片| 婷婷97| 日韩综合第八区国产精品| 伦激情人妻另类人妻| 黄色AV影视| 97操在线| 尤物黄色在线观看网站| 亚洲精品97在线| 少妇的嫩逼图片| 欧美一级国产一级| 天天操女人| 9丨久久九九九| 爱射综合| 国产在线激情| 91精品人妻电影| 综合久久99亚洲人妻中文在线| 日本操逼无码| 97视频网站在线观看| 青草精品视频一日本久久久久网站| 亚洲va有码在线天堂| 91在线限制级| ,成人免费啪啪视频| 7月婷婷综合| 欧美天天射| 99热国产| 九久久精| 久草视频分类在线| 黄久久| 亚洲欧美精品一区天堂久久 | 亚洲国产成人高清在线| 无码九九九九| 1禁看欧美黄片免费看| 欧美综合 站| 久操网址| 亚洲综合另类色图| 中文字幕成人理论在线| 国产99999久久精品| 蜜乳av一区二区| 极品久久久久久久久久久久久久| 第四色奇米影视777| A啊啊在线观看| 黑人无码一区二区| 老色鬼成人精品视频下载大在线观看| 强奸乱伦大香蕉| 蜜臀AV成人精品蜜臀AV久久| 日熟女| 91国产美女丝袜足交精品视频| 国产成年女人免费视频播放a| 97超碰中文| 国产激情片在线观看| 精品少妇一区二区| 久久99操天天日| 久久久久亚洲三级电影| 精品美女少妇一区二区三区| 蜜乳Av成人片网站| 欧美色图 人妻| 欧美性巨大╳╳╳╳╳高跟鞋| 97操综合| 一起草av| 91在线超高颜值国产| 97热视频在线观看| av凤凰久久久| 亚洲成人精品在线一区| 青青草字幕AV| 国产极品一区二区三区三州| 亚洲影视综合| 九一精品牛牛一区二区| 把腿张开老子CAO烂你| 青青草久草AV| 天天综合网~69| 69少妇一区二区| 亚洲男人天堂视频| 偷拍网站久久男女男| 97人人操人人摸| 91欧美www| 色色综合97| 婷婷久热| 国产精品无码成人精品| 欧美少妇高潮视频| 亚洲欧美另类少妇精品| 中文字幕精品区先锋资源| 啪啪啪综合| 骚逼一区二区| 99re在线观看| 伊人天天久久动态图| 9997se| 青青青操| 久久久久国产精品片区无码直播| 伊人网免费视频| 麻豆色约约| 久久久久久中文版| 国产精品一区二区在钱播放| 人人摸人人添人人操| 亚洲精品99999| 亚洲情色 自拍| 欧美亚洲美少妇一区二区| 久久久97| 黄片www.| 国产不良强奸视频免费看| 国产精品一区二区麻豆| 偷拍在线观看视频| 密桃99999| 久草福利在线资源站| 亚洲成人激情小说视频| 人妻激情视频| 九九av| 色婷婷在线视频精品导航| 五月丁香激情综合| 亚洲精美粉嫩嫩泬在线观看| 亚洲欧美伦综合| 欧美日日人人天天| 另类av综合久久| 麻豆一区在线| 夫妻四区五区六区| 日本免费中文一区二区三区四区 | 蜜臀久久99精品久久久老,,| 日韩中文字幕在线视频观看| 亚洲欧美在线观看无码| 国产精品4p在线观看| 日韩97P| 精品人妻久久久| 欧综合网| 欧美少妇高潮| 97色色国产视频| 999 久久久| 久超超碰| 青青草天天亲夜夜操网| 操逼操操操91| 日韩精品在线观看网站| 蜜乳中文字幕a在线| 熟妇乱伦一区二区| 囯产精品久久久久久久久久二区三区| sewuyueav| 精品无av| 九七超碰人人乐| 人妻少妇精品视频一区二区三区| 国产丁香精品露脸视频| 亚洲色图 图片| 日韩图区|