日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java基礎(chǔ) 之軟引用、弱引用、虛引用 ·[轉(zhuǎn)載]

 SheldonDemo 2017-05-02

2011-11-24 14:43:41
Java基礎(chǔ) 之軟引用、弱引用、虛引用
瀏覽(509)|評論(1)   交流分類:Java|筆記分類: Java

1、概述

   在JDK1.2以前的版本中,當(dāng)一個對象不被任何變量引用,那么程序就無法再使用這個對象。也就是說,只有對象處于可觸及狀態(tài),程序才能使用它。這 就像在日常生活中,從商店購買了某樣物品后,如果有用,就一直保留它,否則就把它扔到垃圾箱,由清潔工人收走。一般說來,如果物品已經(jīng)被扔到垃圾箱,想再 把它撿回來使用就不可能了。
   但有時候情況并不這么簡單,你可能會遇到類似雞肋一樣的物品,食之無味,棄之可惜。這種物品現(xiàn)在已經(jīng)無用了,保留它會占空間,但是立刻扔掉它也不劃算,因 為也許將來還會派用場。對于這樣的可有可無的物品,一種折衷的處理辦法是:如果家里空間足夠,就先把它保留在家里,如果家里空間不夠,即使把家里所有的垃 圾清除,還是無法容納那些必不可少的生活用品,那么再扔掉這些可有可無的物品。
   從JDK1.2版本開始,把對象的引用分為四種級別,從而使程序能更加靈活的控制對象的生命周期。這四種級別由高到低依次為:強(qiáng)引用、軟引用、弱引用和虛引用。

下圖為對象層次的引用

2、強(qiáng)引用
   平時我們編程的時候例如:Object object=new Object();那object就是一個強(qiáng)引用了。如果一個對象具有強(qiáng)引用,那就類似于必不可少的生活用品,垃圾回收器絕不會回收它。當(dāng)內(nèi)存空 間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強(qiáng)引用的對象來解決內(nèi)存不足問題。

3、軟引用(SoftReference)
   如果一個對象只具有軟引用,那就類似于可有可物的生活用品。如果內(nèi)存空間足夠,垃圾回收器就不會回收它,如果內(nèi)存空間不足了,就會回收這些對象的內(nèi)存。只 要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存。 軟引用可以和一個引用隊(duì)列(ReferenceQueue)聯(lián) 合使用,如果軟引用所引用的對象被垃圾回收,Java虛擬機(jī)就會把這個軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。


4、弱引用(WeakReference)

   如果一個對象只具有弱引用,那就類似于可有可物的生活用品。弱引用與軟引用的區(qū)別在于:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它 所管轄的內(nèi)存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對象,不管當(dāng)前內(nèi)存空間足夠與否,都會回收它的內(nèi)存。不過,由于垃圾回收器是一個優(yōu)先級很低的線程, 因此不一定會很快發(fā)現(xiàn)那些只具有弱引用的對象。  弱引用可以和一個引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對象被垃圾回 收,Java虛擬機(jī)就會把這個弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。 

 5、虛引用(PhantomReference)

   '虛引用'顧名思義,就是形同虛設(shè),與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在 任何時候都可能被垃圾回收。 虛引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區(qū)別在于:虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個對象時,如果發(fā)現(xiàn)它還有虛引用,就會在回收對象的內(nèi)存之前,把這個虛引用加入到與之 關(guān)聯(lián)的引用隊(duì)列中。程序可以通過判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序如果發(fā)現(xiàn)某個虛引用已經(jīng)被加入到引用隊(duì) 列,那么就可以在所引用的對象的內(nèi)存被回收之前采取必要的行動。 

6、相關(guān)應(yīng)用

  在java.lang.ref包中提供了三個類:SoftReference類、WeakReference類和PhantomReference類,它 們分別代表軟引用、弱引用和虛引用。ReferenceQueue類表示引用隊(duì)列,它可以和這三種引用類聯(lián)合使用,以便跟蹤Java虛擬機(jī)回收所引用的對 象的活動。

以下程序創(chuàng)建了一個String對象、ReferenceQueue對象和WeakReference對象:

以上程序代碼執(zhí)行完畢,內(nèi)存中引用與對象的關(guān)系如圖2所示



       圖2 'hello'對象同時具有強(qiáng)引用和弱引用

     在圖2中,帶實(shí)線的箭頭表示強(qiáng)引用,帶虛線的箭頭表示弱引用。從圖中可以看出,此時'hello'對象被str強(qiáng)引用,并且被一個WeakReference對象弱引用,因此'hello'對象不會被垃圾回收。

   在以下程序代碼中,把引用'hello'對象的str變量置為null,然后再通過WeakReference弱引用的get()方法獲得'hello'對象的引用:

    執(zhí)行完以上第④行后,內(nèi)存中引用與對象的關(guān)系如圖3所示,此 時'hello'對象僅僅具有弱引用,因此它有可能被垃圾回收。假如它還沒有被垃圾回收,那么接下來在第⑤行執(zhí)行wf.get()方法會返回 'hello'對象的引用,并且使得這個對象被str1強(qiáng)引用。再接下來在第⑥行執(zhí)行rq.poll()方法會返回null,因?yàn)榇藭r引用隊(duì)列中沒有任何 引用。ReferenceQueue的poll()方法用于返回隊(duì)列中的引用,如果沒有則返回null。



     圖3 'hello'對象只具有弱引用

    在以下程序代碼中,執(zhí)行完第④行后,'hello'對象僅僅具有弱引用。接下來兩次調(diào)用System.gc()方法,催促垃圾回收器工作,從而提高 'hello'對象被回收的可能性。假如'hello'對象被回收,那么WeakReference對象的引用被加入到ReferenceQueue中, 接下來wf.get()方法返回null,并且rq.poll()方法返回WeakReference對象的引用。圖4顯示了執(zhí)行完第⑧行后內(nèi)存中引用與 對象的關(guān)系。



  圖4 'hello'對象被垃圾回收,弱引用被加入到引用隊(duì)列

    在以下代碼References類中,依次創(chuàng)建了10個軟引用、10個弱引用和10個虛引用,它們各自引用一個Grocery對象。從程序運(yùn) 行時的打印結(jié)果可以看出,虛引用形同虛設(shè),它所引用的對象隨時可能被垃圾回收,具有弱引用的對象擁有稍微長的生命周期,當(dāng)垃圾回收器執(zhí)行回收操作時,有可 能被垃圾回收,具有軟引用的對象擁有較長的生命周期,但在Java虛擬機(jī)認(rèn)為內(nèi)存不足的情況下,也會被垃圾回收。

     在Java集合中有一種特殊的Map類型:WeakHashMap, 在這種Map中存放了鍵對象的弱引用,當(dāng)一個鍵對象被垃圾回收,那么相應(yīng)的值對象的引用會從Map中刪除。WeakHashMap能夠節(jié)約存儲空間,可用來緩存那些非必須存在的數(shù)據(jù)。
     以下代碼MapCache類的main()方法創(chuàng)建了一個WeakHashMap對象,它存放了一組Key對象的弱引用,此外main()方法還創(chuàng)建了一個數(shù)組對象,它存放了部分Key對象的強(qiáng)引用。

程序輸出結(jié)果:

    從打印結(jié)果可以看出,當(dāng)執(zhí)行System.gc()方法后,垃圾回收器只會回收那些僅僅持有弱引用的Key對象。id可以被3整數(shù)的Key對象持有強(qiáng)引用,因此不會被回收。

7、使用軟引用構(gòu)建敏感數(shù)據(jù)的緩存

    7.1 為什么需要使用軟引用
    首先,我們看一個雇員信息查詢系統(tǒng)的實(shí)例。我們將使用一個Java語言實(shí)現(xiàn)的雇員信息查詢系統(tǒng)查詢存儲在磁盤文件或者數(shù)據(jù)庫中的雇員人事檔案信息。作為一 個用戶,我們完全有可能需要回頭去查看幾分鐘甚至幾秒鐘前查看過的雇員檔案信息(同樣,我們在瀏覽WEB頁面的時候也經(jīng)常會使用“后退”按鈕)。這時我們 通常會有兩種程序?qū)崿F(xiàn)方式:一種是把過去查看過的雇員信息保存在內(nèi)存中,每一個存儲了雇員檔案信息的Java對象的生命周期貫穿整個應(yīng)用程序始終;另一種 是當(dāng)用戶開始查看其他雇員的檔案信息的時候,把存儲了當(dāng)前所查看的雇員檔案信息的Java對象結(jié)束引用,使得垃圾收集線程可以回收其所占用的內(nèi)存空間,當(dāng) 用戶再次需要瀏覽該雇員的檔案信息的時候,重新構(gòu)建該雇員的信息。很顯然,第一種實(shí)現(xiàn)方法將造成大量的內(nèi)存浪費(fèi),而第二種實(shí)現(xiàn)的缺陷在于即使垃圾收集線程 還沒有進(jìn)行垃圾收集,包含雇員檔案信息的對象仍然完好地保存在內(nèi)存中,應(yīng)用程序也要重新構(gòu)建一個對象。我們知道,訪問磁盤文件、訪問網(wǎng)絡(luò)資源、查詢數(shù)據(jù)庫 等操作都是影響應(yīng)用程序執(zhí)行性能的重要因素,如果能重新獲取那些尚未被回收的Java對象的引用,必將減少不必要的訪問,大大提高程序的運(yùn)行速度。


    7.2 如果使用軟引用
    SoftReference的特點(diǎn)是它的一個實(shí)例保存對一個Java對象的軟引用,該軟引用的存在不妨礙垃圾收集線程對該Java對象的回收。也就是說, 一旦SoftReference保存了對一個Java對象的軟引用后,在垃圾線程對這個Java對象回收前,SoftReference類所提供的 get()方法返回Java對象的強(qiáng)引用。另外,一旦垃圾線程回收該Java對象之后,get()方法將返回null。

 看下面代碼:

     此時,對于這個MyObject對象,有兩個引用路徑,一個是來自SoftReference對象的軟引用,一個來自變量aReference的強(qiáng)引用,所以這個MyObject對象是強(qiáng)可及對象。
     隨即,我們可以結(jié)束aReference對這個MyObject實(shí)例的強(qiáng)引用:
     aRef = null; 
     此后,這個MyObject對象成為了軟可及對象。如果垃圾收集線程進(jìn)行內(nèi)存垃圾收集,并不會因?yàn)橛幸粋€SoftReference對該對象的引用而始終 保留該對象。Java虛擬機(jī)的垃圾收集線程對軟可及對象和其他一般Java對象進(jìn)行了區(qū)別對待:軟可及對象的清理是由垃圾收集線程根據(jù)其特定算法按照內(nèi)存 需求決定的。也就是說,垃圾收集線程會在虛擬機(jī)拋出OutOfMemoryError之前回收軟可及對象,而且虛擬機(jī)會盡可能優(yōu)先回收長時間閑置不用的軟 可及對象,對那些剛剛構(gòu)建的或剛剛使用過的“新”軟可反對象會被虛擬機(jī)盡可能保留。在回收這些對象之前,我們可以通過:
     MyObject anotherRef=(MyObject)aSoftRef.get(); 
     重新獲得對該實(shí)例的強(qiáng)引用。而回收之后,調(diào)用get()方法就只能得到null了。


     7.3 使用ReferenceQueue清除失去了軟引用對象的SoftReference
     作為一個Java對象,SoftReference對象除了具有保存軟引用的特殊性之外,也具有Java對象的一般性。所以,當(dāng)軟可及對象被回收之后, 雖然這個SoftReference對象的get()方法返回null,但這個SoftReference對象已經(jīng)不再具有存在的價值,需要一個適當(dāng)?shù)那?除機(jī)制,避免大量SoftReference對象帶來的內(nèi)存泄漏。在java.lang.ref包里還提供了ReferenceQueue。如果在創(chuàng)建 SoftReference對象的時候,使用了一個ReferenceQueue對象作為參數(shù)提供給SoftReference的構(gòu)造方法,如:

    那么當(dāng)這個SoftReference所軟引用的aMyOhject被垃圾收集器回收的同時,ref所強(qiáng)引用的SoftReference對象被列入 ReferenceQueue。也就是說,ReferenceQueue中保存的對象是Reference對象,而且是已經(jīng)失去了它所軟引用的對象的 Reference對象。另外從ReferenceQueue這個名字也可以看出,它是一個隊(duì)列,當(dāng)我們調(diào)用它的poll()方法的時候,如果這個隊(duì)列中 不是空隊(duì)列,那么將返回隊(duì)列前面的那個Reference對象。
    在任何時候,我們都可以調(diào)用ReferenceQueue的poll()方法來檢查是否有它所關(guān)心的非強(qiáng)可及對象被回收。如果隊(duì)列為空,將返回一個 null,否則該方法返回隊(duì)列中前面的一個Reference對象。利用這個方法,我們可以檢查哪個SoftReference所軟引用的對象已經(jīng)被回 收。于是我們可以把這些失去所軟引用的對象的SoftReference對象清除掉。常用的方式為:

     理解了ReferenceQueue的工作機(jī)制之后,我們就可以開始構(gòu)造一個Java對象的高速緩存器了。


     7.4通過軟可及對象重獲方法實(shí)現(xiàn)Java對象的高速緩存
 利用Java2平臺垃圾收集機(jī)制的特性以及前述的垃圾對象重獲方法,我們通過一個雇員信息查詢系統(tǒng)的小例子來說明如何構(gòu)建一種高速緩存器來避免重復(fù)構(gòu)建同一個對象帶來的性能損失。我們將一個雇員的檔案信息定義為一個Employee類:

    這個Employee類的構(gòu)造方法中我們可以預(yù)見,如果每次需要查詢一個雇員的信息。哪怕是幾秒中之前剛剛查詢過的,都要重新構(gòu)建一個實(shí)例,這是需要消耗很多時間的。下面是一個對Employee對象進(jìn)行緩存的緩存器的定義:

java代碼:
  1. import java.lang.ref.ReferenceQueue;      
  2. import java.lang.ref.SoftReference;      
  3. import java.util.Hashtable;      
  4. publicclass EmployeeCache {      
  5. staticprivate EmployeeCache cache;// 一個Cache實(shí)例    
  6. private Hashtable employeeRefs;// 用于Cache內(nèi)容的存儲    
  7. private ReferenceQueue q;// 垃圾Reference的隊(duì)列    
  8. // 繼承SoftReference,使得每一個實(shí)例都具有可識別的標(biāo)識。    
  9. // 并且該標(biāo)識與其在HashMap內(nèi)的key相同。    
  10. privateclass EmployeeRef extends SoftReference {      
  11. private String _key = '';      
  12. public EmployeeRef(Employee em, ReferenceQueue q) {      
  13. super(em, q);      
  14.            _key = em.getID();      
  15.        }      
  16.     }      
  17. // 構(gòu)建一個緩存器實(shí)例    
  18. private EmployeeCache() {      
  19.        employeeRefs = new Hashtable();      
  20.        q = new ReferenceQueue();      
  21.     }      
  22. // 取得緩存器實(shí)例    
  23. publicstatic EmployeeCache getInstance() {      
  24. if (cache == null) {      
  25.            cache = new EmployeeCache();      
  26.        }      
  27. return cache;      
  28.     }      
  29. // 以軟引用的方式對一個Employee對象的實(shí)例進(jìn)行引用并保存該引用    
  30. privatevoid cacheEmployee(Employee em) {      
  31.        cleanCache();// 清除垃圾引用    
  32.        EmployeeRef ref = new EmployeeRef(em, q);      
  33.        employeeRefs.put(em.getID(), ref);      
  34.     }      
  35. // 依據(jù)所指定的ID號,重新獲取相應(yīng)Employee對象的實(shí)例    
  36. public Employee getEmployee(String ID) {      
  37.        Employee em = null;      
  38. // 緩存中是否有該Employee實(shí)例的軟引用,如果有,從軟引用中取得。    
  39. if (employeeRefs.containsKey(ID)) {      
  40.            EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID);      
  41.            em = (Employee) ref.get();      
  42.        }      
  43. // 如果沒有軟引用,或者從軟引用中得到的實(shí)例是null,重新構(gòu)建一個實(shí)例,    
  44. // 并保存對這個新建實(shí)例的軟引用    
  45. if (em == null) {      
  46.            em = new Employee(ID);      
  47.            System.out.println('Retrieve From EmployeeInfoCenter. ID='   ID);      
  48. this.cacheEmployee(em);      
  49.        }      
  50. return em;      
  51.     }      
  52. // 清除那些所軟引用的Employee對象已經(jīng)被回收的EmployeeRef對象    
  53. privatevoid cleanCache() {      
  54.        EmployeeRef ref = null;      
  55. while ((ref = (EmployeeRef) q.poll()) != null) {      
  56.            employeeRefs.remove(ref._key);      
  57.        }      
  58.     }      
  59. // 清除Cache內(nèi)的全部內(nèi)容    
  60. publicvoid clearCache() {      
  61.        cleanCache();      
  62.        employeeRefs.clear();      
  63.        System.gc();      
  64.        System.runFinalization();      
  65.     }      
  66. }      

 8.使用弱引用構(gòu)建非敏感數(shù)據(jù)的緩存
     8.1全局 Map 造成的內(nèi)存泄漏
     無意識對象保留最常見的原因是使用Map將元數(shù)據(jù)與臨時對象(transient object)相關(guān)聯(lián)。假定一個對象具有中等生命周期,比分配它的那個方法調(diào)用的生命周期長,但是比應(yīng)用程序的生命周期短,如客戶機(jī)的套接字連接。需要將 一些元數(shù)據(jù)與這個套接字關(guān)聯(lián),如生成連接的用戶的標(biāo)識。在創(chuàng)建Socket時是不知道這些信息的,并且不能將數(shù)據(jù)添加到Socket對象上,因?yàn)椴荒芸刂?Socket 類或者它的子類。這時,典型的方法就是在一個全局 Map 中存儲這些信息,如下面的 SocketManager 類所示:使用一個全局 Map 將元數(shù)據(jù)關(guān)聯(lián)到一個對象。

    這種方法的問題是元數(shù)據(jù)的生命周期需要與套接字的生命周期掛鉤,但是除非準(zhǔn)確地知道什么時候程序不再需要這個套接字,并記住從 Map 中刪除相應(yīng)的映射,否則,Socket 和 User 對象將會永遠(yuǎn)留在 Map 中,遠(yuǎn)遠(yuǎn)超過響應(yīng)了請求和關(guān)閉套接字的時間。這會阻止 Socket 和 User 對象被垃圾收集,即使應(yīng)用程序不會再使用它們。這些對象留下來不受控制,很容易造成程序在長時間運(yùn)行后內(nèi)存爆滿。除了最簡單的情況,在幾乎所有情況下找出 什么時候 Socket 不再被程序使用是一件很煩人和容易出錯的任務(wù),需要人工對內(nèi)存進(jìn)行管理。


     8.2如何使用WeakHashMap
     在Java集合中有一種特殊的Map類型—WeakHashMap,在這種Map中存放了鍵對象的弱引用,當(dāng)一個鍵對象被垃圾回收器回收時,那么相應(yīng)的值 對象的引用會從Map中刪除。WeakHashMap能夠節(jié)約存儲空間,可用來緩存那些非必須存在的數(shù)據(jù)。關(guān)于Map接口的一般用法。
    下面示例中MapCache類的main()方法創(chuàng)建了一個WeakHashMap對象,它存放了一組Key對象的弱引用,此外main()方法還創(chuàng)建了一個數(shù)組對象,它存放了部分Key對象的強(qiáng)引用。

java代碼:
  1. import java.util.WeakHashMap;      
  2. class Element {      
  3. private String ident;      
  4. public Element(String id) {      
  5.        ident = id;      
  6.     }      
  7. public String toString() {      
  8. return ident;      
  9.     }      
  10. publicint hashCode() {      
  11. return ident.hashCode();      
  12.     }      
  13. publicboolean equals(Object obj) {      
  14. return obj instanceof Element && ident.equals(((Element) obj).ident);      
  15.     }      
  16. protectedvoid finalize(){      
  17.        System.out.println('Finalizing ' getClass().getSimpleName() ' ' ident);      
  18.     }      
  19. }      
  20. class Key extends Element{      
  21. public Key(String id){      
  22. super(id);      
  23.     }      
  24. }      
  25. class Value extends Element{      
  26. public Value (String id){      
  27. super(id);      
  28.     }      
  29. }      
  30. publicclass CanonicalMapping {      
  31. publicstaticvoid main(String[] args){      
  32. int size=1000;      
  33.        Key[] keys=new Key[size];      
  34.        WeakHashMap map=new WeakHashMap();      
  35. for(int i=0;i< SPAN>    
  36.            Key k=new Key(Integer.toString(i));      
  37.            Value v=new Value(Integer.toString(i));      
  38. if(i%3==0)      
  39.               keys[i]=k;      
  40.            map.put(k, v);      
  41.        }      
  42.        System.gc();      
  43.     }      
  44. }      

     從打印結(jié)果可以看出,當(dāng)執(zhí)行System.gc()方法后,垃圾回收器只會回收那些僅僅持有弱引用的Key對象。id可以被3整除的Key對象持有強(qiáng)引用,因此不會被回收。


    8.3用 WeakHashMap 堵住泄漏
    在 SocketManager 中防止泄漏很容易,只要用 WeakHashMap 代替 HashMap 就行了。(這里假定SocketManager不需要線程安全)。當(dāng)映射的生命周期必須與鍵的生命周期聯(lián)系在一起時,可以使用這種方法。用 WeakHashMap修復(fù) SocketManager。

     8.4配合使用引用隊(duì)列
     WeakHashMap 用弱引用承載映射鍵,這使得應(yīng)用程序不再使用鍵對象時它們可以被垃圾收集,get() 實(shí)現(xiàn)可以根據(jù) WeakReference.get() 是否返回 null 來區(qū)分死的映射和活的映射。但是這只是防止 Map 的內(nèi)存消耗在應(yīng)用程序的生命周期中不斷增加所需要做的工作的一半,還需要做一些工作以便在鍵對象被收集后從 Map 中刪除死項(xiàng)。否則,Map 會充滿對應(yīng)于死鍵的項(xiàng)。雖然這對于應(yīng)用程序是不可見的,但是它仍然會造成應(yīng)用程序耗盡內(nèi)存。 
 引用隊(duì)列是垃圾收集器向應(yīng)用程序返回關(guān)于對象生命周期的信息的主要方法。弱引用有個構(gòu)造函數(shù)取引用隊(duì)列作為參數(shù)。如果用關(guān)聯(lián)的引用隊(duì)列創(chuàng)建弱引用,在弱引用對象成為 GC 候選對象時,這個引用對象就在引用清除后加入到引用隊(duì)列中(具體參考上文軟引用示例)。
     WeakHashMap 有一個名為 expungeStaleEntries() 的私有方法,大多數(shù) Map 操作中會調(diào)用它,它去掉引用隊(duì)列中所有失效的引用,并刪除關(guān)聯(lián)的映射。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多