內(nèi)存泄漏全解析

作者簡(jiǎn)介 原創(chuàng)微信公眾號(hào)郭霖 WeChat ID: guolin_blog

本篇是南塵的第二篇投稿瞻想,全方位分析了導(dǎo)致內(nèi)存泄漏的原因蠕啄,并給出解決方案丧没。希望能夠幫助到大家们拙。

南塵的博客地址:

http://www.cnblogs.com/liushilin

寫在前面

對(duì)于 C++ 來說癞季,內(nèi)存泄漏就是new出來的對(duì)象沒有 delete劫瞳,俗稱野指針;而對(duì)于 java 來說绷柒,就是 new 出來的 Object 放在 Heap 上無法被GC回收志于;而這里就把我之前的一篇內(nèi)存泄漏的總結(jié)翻新,做一個(gè)更加全面規(guī)范的講解废睦,希望能幫到各位伺绽。

一些雜談

java的內(nèi)存分配

靜態(tài)存儲(chǔ)區(qū):編譯時(shí)就分配好,在程序整個(gè)運(yùn)行期間都存在嗜湃。它主要存放靜態(tài)數(shù)據(jù)和常量奈应;

棧區(qū):當(dāng)方法執(zhí)行時(shí),會(huì)在棧區(qū)內(nèi)存中創(chuàng)建方法體內(nèi)部的局部變量购披,方法結(jié)束后自動(dòng)釋放內(nèi)存杖挣;

堆區(qū):通常用來存放new出來的對(duì)象。由java垃圾回收期回收刚陡。

四種引用類型的介紹

強(qiáng)引用(StrongReference):JVM 寧可拋出 OOM 惩妇,也不會(huì)讓 GC 回收具有強(qiáng)引用的對(duì)象;

軟引用(SoftReference):只有在內(nèi)存空間不足時(shí)筐乳,才會(huì)被回的對(duì)象歌殃;

弱引用(WeakReference):在 GC 時(shí),一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象蝙云,不管當(dāng)前內(nèi)存空間足夠與否挺份,都會(huì)回收它的內(nèi)存;

虛引用(PhantomReference):任何時(shí)候都可以被GC回收贮懈,當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí)匀泊,如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前朵你,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中各聘。程序可以通過判斷引用隊(duì)列中是否存在該對(duì)象的虛引用,來了解這個(gè)對(duì)象是否將要被回收抡医《阋颍可以用來作為GC回收Object的標(biāo)志。

內(nèi)存抖動(dòng)

這樣的圖很熟悉有木有忌傻?當(dāng)這樣的時(shí)候大脉,說明你的內(nèi)存真的在變少了。

內(nèi)存泄漏檢測(cè)工具

1.MAT(Memory Analyzer Tool)水孩,下載地址:

http://www.eclipse.org/mat/downloads.php

具體使用這個(gè)網(wǎng)上一大篇镰矿,樓主一有時(shí)間也會(huì)為大家一步步奉上。

2.強(qiáng)大的開源內(nèi)存檢測(cè)工具 LeakCanary俘种。

leakcanary 是一個(gè)開源項(xiàng)目秤标,一個(gè)內(nèi)存泄露自動(dòng)檢測(cè)工具,是著名的 GitHub 開源組織 Square 貢獻(xiàn)的宙刘,它的主要優(yōu)勢(shì)就在于自動(dòng)化過早的發(fā)覺內(nèi)存泄露苍姜、配置簡(jiǎn)單、抓取貼心悬包,缺點(diǎn)在于還存在一些bug衙猪,不過正常使用百分之九十情況是OK的,其核心原理與MAT工具類似布近。

因?yàn)榕渲檬趾?jiǎn)單垫释,只需要幾句話就好!5跏洹饶号!這里就不多說了,大家可以看官方文檔:

https://github.com/square/leakcanary

內(nèi)存泄漏解析

永遠(yuǎn)的Singleton

單例的使用在我們的程序中隨處可見季蚂,因?yàn)槭褂盟梢酝昝赖慕鉀Q我們?cè)诔绦蛑兄貜?fù)創(chuàng)建對(duì)象的問題茫船,不過可別小瞧它。由于單例的靜態(tài)特性扭屁,使得它的生命周期和應(yīng)用的生命周期會(huì)一樣長(zhǎng)算谈,所以一旦使用有誤,小心無限制的持有Activity的引用而導(dǎo)致內(nèi)存泄漏料滥。比如然眼,下面的例子。

這個(gè)錯(cuò)誤在生活中再普遍不過葵腹,很正常的一個(gè)單例模式高每,可就由于傳入的是一個(gè) Context屿岂,而這個(gè) Context 的生命周期的長(zhǎng)短就尤為重要了。如果我們傳入的是 Activity 的 Context鲸匿,當(dāng)這個(gè) Context 所對(duì)應(yīng)的 Activity 退出的時(shí)候爷怀,由于該 Context 的引用被單例對(duì)象所持有,其生命周期等于整個(gè)應(yīng)用程序的生命周期带欢,所以當(dāng)前 Activity 退出時(shí)它的內(nèi)存并不會(huì)回收运授,這造成的內(nèi)存泄漏就可想而知了。

正確的方式應(yīng)該是把傳入的 Context 換為和應(yīng)用的生命周期一樣長(zhǎng)的 Application 的 Context:

當(dāng)然乔煞,你也可以直接連 Context 都不用傳入了吁朦。重寫 application,提供靜態(tài)的 getContext 方法:

自然就可以直接不用傳入Context:

令人心塞的Handler

這個(gè)東西在我最近遇到的最多了渡贾,而它也是我們?cè)趦?nèi)存泄漏中最為常見的逗宜,也許你的一個(gè)小忽略就會(huì)導(dǎo)致內(nèi)存泄漏。在Android的新版本中剥啤,我們被要求必須把網(wǎng)絡(luò)任務(wù)等耗時(shí)操作置于新線程來處理锦溪,我們通常會(huì)采用 Handler。

但 Handler 不是萬能的府怯,若是我們的編寫不規(guī)范就有可能會(huì)造成內(nèi)存泄漏刻诊。另外,我們知道牺丙,Handler则涯、Message 和 MessageQueue 都是相互關(guān)聯(lián)在一起的,萬一 Handler 發(fā)送的 Message 尚未被處理冲簿,則該 Message 及發(fā)送它的 Handler 對(duì)象將會(huì)被線程 MessageQueue 一直持有粟判。

由于 Handler 屬于 TLS(Thread Local Storage)變量,生命周期和 Activity 是不一致的峦剔。因此這種實(shí)現(xiàn)方式一般很難保證跟 View 或者 Activity 的生命周期一致档礁,故很容易導(dǎo)致無法正確釋放。比如:

在例子中吝沫,我們申明了一個(gè)延遲5分鐘執(zhí)行的消息 Message呻澜。當(dāng)該 Activity 被 finish 的時(shí)候,延遲任務(wù)的 Message 還存在于主線程中惨险,它持有該 Activity 的 Handler 引用羹幸,所以此時(shí) finish 掉的 Activity 就不會(huì)回收了,所以造成了內(nèi)存泄漏(因 handler 為非靜態(tài)內(nèi)部類辫愉,它會(huì)持有外部類的引用栅受,在這里就是當(dāng)前的 Activity)。

修復(fù):這個(gè)解決也是可以通過把其聲明為 static 的,則其存活期就跟 activity 的生命周期無關(guān)了屏镊。不過倘若用到 Context 等外部類的 非static 對(duì)象依疼,還是應(yīng)該通過弱引用傳入。比如:

綜述:推薦使用靜態(tài)內(nèi)部類+弱引用 WeakReference 這種方式闸衫,但要注意每次使用前判空涛贯。

說到若引用,這里再提下java的幾種引用類型:Strong, reference,SoftReference,WeakReference 和 PhatomReference:

在 Android 開發(fā)中蔚出,為了防止內(nèi)存溢出,在處理一些占用內(nèi)存大并且生命周期較長(zhǎng)的對(duì)象的時(shí)候虫腋,可以盡量地使用 軟引用 和 弱引用 技術(shù)骄酗。

比如,保存 Bitmap 的軟引用到 HashMap:

使用軟引用以后悦冀,在 OutOfMemory 異常發(fā)生之前趋翻,這些緩存的圖片資源的內(nèi)存空間可以被釋放掉的,從而避免內(nèi)存達(dá)到上限盒蟆,避免Crash發(fā)生踏烙。

如果只是想避免 OutOfMemory 異常的發(fā)生,則可以使用 軟引用历等。如果對(duì)于應(yīng)用的性能更在意讨惩,想盡快回收一些占用內(nèi)存比較大的對(duì)象,則可以使用 弱引用寒屯。

另外可以根據(jù)對(duì)象是否經(jīng)常使用來判斷選擇 軟引用 還是 弱引用荐捻。如果該對(duì)象可能會(huì)經(jīng)常使用的,就盡量用 軟引用寡夹。如果該對(duì)象不被使用的可能性更大些处面,就可以用 弱引用。

ok菩掏,繼續(xù)回到主題魂角。前面所說的,創(chuàng)建一個(gè) 靜態(tài)Handler內(nèi)部類智绸,然后對(duì) Handler 持有的對(duì)象使用弱引用野揪,這樣在回收時(shí)也可以回收 Handler 持有的對(duì)象,但是這樣做雖然避免了 Activity 泄漏传于,不過 Looper 線程的消息隊(duì)列中還是可能會(huì)有待處理的消息囱挑,所以我們?cè)?Activity 的 Destroy 時(shí)或者 Stop 時(shí)應(yīng)該移除消息隊(duì)列 MessageQueue 中的消息。

下面幾個(gè)方法都可以移除 Message:

匿名內(nèi)部類/非靜態(tài)內(nèi)部類

它們方便卻暗藏殺機(jī)沼溜。Android開發(fā)經(jīng)常會(huì)繼承實(shí)現(xiàn) Activity 或者 Fragment 或者 View平挑。如果你使用了匿名類,而又被異步線程所引用,那得小心通熄,如果沒有任何措施同樣會(huì)導(dǎo)致內(nèi)存泄漏的:

runnable1runnable2的區(qū)別就是唆涝,runnable2 使用了匿名內(nèi)部類,我們看看引用時(shí)的引用內(nèi)存:

可以看到唇辨,runnable1 是沒有什么特別的廊酣。但 runnable2 多出了一個(gè) MainActivity 的引用,若是這個(gè)引用再傳入到一個(gè)異步線程赏枚,此線程在和Activity生命周期不一致的時(shí)候亡驰,也就造成了Activity的泄露。

前輩箴言——善用static成員變量

前面就很明顯饿幅,當(dāng)我們的成員變量是static的時(shí)候凡辱,那么它的生命周期將和整個(gè)app的生命周期一致。

這必然會(huì)導(dǎo)致一系列問題栗恩,如果你的app進(jìn)程設(shè)計(jì)上是長(zhǎng)駐內(nèi)存的透乾,那即使app切到后臺(tái),這部分內(nèi)存也不會(huì)被釋放磕秤。按照現(xiàn)在手機(jī)app內(nèi)存管理機(jī)制乳乌,占內(nèi)存較大的后臺(tái)進(jìn)程將優(yōu)先回收,因?yàn)槿绻薬pp做過進(jìn)程互保笔信兀活汉操,那會(huì)造成app在后臺(tái)頻繁重啟。當(dāng)手機(jī)安裝了你參與開發(fā)的app以后一夜時(shí)間手機(jī)被消耗空了電量床绪、流量客情,你的app不得不被用戶卸載或者靜默。

這里修復(fù)的方法是:

不要在類初始時(shí)初始化靜態(tài)成員癞己“蛘可以考慮 lazy初始化(延遲加載)肿男。架構(gòu)設(shè)計(jì)上要思考是否真的有必要這樣做勃蜘,盡量避免。如果架構(gòu)需要這么設(shè)計(jì)玷氏,那么此對(duì)象的生命周期你有責(zé)任管理起來绩社。

遠(yuǎn)離非靜態(tài)內(nèi)部類和匿名類摔蓝,多用private static class

在我們的日常代碼中,這樣的情況似乎很常見愉耙,及直接寫一個(gè)class就這么光禿禿的情況贮尉。

這樣就在 Activity 內(nèi)部創(chuàng)建了一個(gè)非靜態(tài)內(nèi)部類的單例,每次啟動(dòng) Activity 時(shí)都會(huì)使用該單例的數(shù)據(jù)朴沿,這樣雖然避免了資源的重復(fù)創(chuàng)建猜谚,不過這種寫法卻會(huì)造成內(nèi)存泄漏败砂,因?yàn)榉庆o態(tài)內(nèi)部類默認(rèn)會(huì)持有外部類的引用,而該非靜態(tài)內(nèi)部類又創(chuàng)建了一個(gè)靜態(tài)的實(shí)例魏铅,該實(shí)例的生命周期和應(yīng)用的一樣長(zhǎng)昌犹,這就導(dǎo)致了該靜態(tài)實(shí)例一直會(huì)持有該 Activity 的引用,導(dǎo)致 Activity 的內(nèi)存資源不能正忱婪迹回收斜姥。正確的做法為:

將該內(nèi)部類設(shè)為靜態(tài)內(nèi)部類或?qū)⒃搩?nèi)部類抽取出來封裝成一個(gè)單例,如果需要使用 Context沧竟,請(qǐng)按照上面推薦的使用 Application 的 Context铸敏。當(dāng)然,Application 的 context ?不是萬能的屯仗,所以也不能隨便亂用搞坝,對(duì)于有些地方則必須使用 Activity 的 Context,對(duì)于Application魁袜,Service,Activity三者的 Context 的應(yīng)用場(chǎng)景如下:

其中: NO1 表示 Application 和 Service 可以啟動(dòng)一個(gè) Activity敦第,不過需要?jiǎng)?chuàng)建一個(gè)新的 task 任務(wù)隊(duì)列峰弹。而對(duì)于 Dialog 而言,只有在 Activity 中才能創(chuàng)建芜果。

集合對(duì)象善清除鞠呈,以免內(nèi)存泄漏觸不及防

我們通常會(huì)把一些對(duì)象的引用加入到集合容器(比如 ArrayList)中,當(dāng)我們不再需要該對(duì)象時(shí)右钾,并沒有把它的引用從集合中清理掉蚁吝,這樣這個(gè)集合就會(huì)越來越大。如果這個(gè)集合是 static 的話舀射,那情況就更嚴(yán)重了窘茁。

所以在退出程序之前,將集合里面的東西 clear脆烟,然后置為 null山林,再退出程序,如下:

webView雖火邢羔,內(nèi)存泄漏卻也火的其所

當(dāng)我們不再需要使用 webView 的時(shí)候驼抹,應(yīng)該調(diào)用它的 destory() 方法來銷毀它,并釋放其占用的內(nèi)存拜鹤,否則其占用的內(nèi)存長(zhǎng)期也不能回收框冀,從而造成內(nèi)存泄漏。

解決方案:為 webView 開啟另外一個(gè)進(jìn)程敏簿,通過AIDL與主線程進(jìn)行通信明也,webView 所在的進(jìn)程可以根據(jù)業(yè)務(wù)的需要選擇合適的時(shí)機(jī)進(jìn)行銷毀,從而達(dá)到內(nèi)存的完整釋放。

而另外一些諸如 listView 的 Adapter 沒有緩存之類的這里就不再多提了诡右。

做一個(gè)小的總結(jié)

構(gòu)造 Adapter 時(shí)安岂,沒有使用緩存的 convertView

Bitmap 對(duì)象不在使用時(shí)調(diào)用 recycle() 釋放內(nèi)存

Context 使用不當(dāng)造成內(nèi)存泄露:不要對(duì)一個(gè) Activity Context 保持長(zhǎng)生命周期的引用。盡量在一切可以使用應(yīng)用 ApplicationContext 代替 Context 的地方進(jìn)行替換帆吻。

非靜態(tài)內(nèi)部類的靜態(tài)實(shí)例容易造成內(nèi)存泄漏:即一個(gè)類中如果你不能夠控制它其中內(nèi)部類的生命周期(譬如Activity中的一些特殊Handler等)域那,則盡量使用靜態(tài)類和弱引用來處理(譬如ViewRoot的實(shí)現(xiàn))。

警惕線程未終止造成的內(nèi)存泄露猜煮;譬如在 Activity 中關(guān)聯(lián)了一個(gè)生命周期超過 Activity 的 Thread次员,在退出 Activity 時(shí)切記結(jié)束線程。一個(gè)典型的例子就是 HandlerThread 的 run 方法是一個(gè)死循環(huán)王带,它不會(huì)自己結(jié)束淑蔚,線程的生命周期超過了 Activity 生命周期,我們必須手動(dòng)在Activity的銷毀方法中中調(diào)運(yùn) thread.getLooper().quit(); 才不會(huì)泄露愕撰。

對(duì)象的注冊(cè)與反注冊(cè)沒有成對(duì)出現(xiàn)造成的內(nèi)存泄露刹衫;譬如注冊(cè)廣播接收器、注冊(cè)觀察者(典型的譬如數(shù)據(jù)庫的監(jiān)聽)等搞挣。

創(chuàng)建與關(guān)閉沒有成對(duì)出現(xiàn)造成的泄露带迟;譬如 Cursor 資源必須手動(dòng)關(guān)閉,WebView 必須手動(dòng)銷毀囱桨,流等對(duì)象必須手動(dòng)關(guān)閉等仓犬。

不要在執(zhí)行頻率很高的方法或者循環(huán)中創(chuàng)建對(duì)象(比如onmeasure),可以使用 HashTable 等創(chuàng)建一組對(duì)象容器從容器中取那些對(duì)象舍肠,而不用每次new與釋放搀继。

避免代碼設(shè)計(jì)模式的錯(cuò)誤造成內(nèi)存泄露;譬如循環(huán)引用翠语,A持有B叽躯,B持有C,C持有A啡专,這樣的設(shè)計(jì)誰都得不到釋放险毁。

真相只有一個(gè)

內(nèi)存泄漏實(shí)在太普遍了,真是防不勝防们童。不過我想告訴廣大的小伙伴畔况,程序員嘛,誰還不踩個(gè)坑慧库,跳出來跷跪,拍拍身上的灰塵,總結(jié)一下齐板,過兩天又是一條幫幫的coder吵瞻。你可以的


完葛菇。。橡羞。眯停。。卿泽。莺债。。签夭。齐邦。。第租。措拇。。慎宾。丐吓。。趟据。汰蜘。。之宿。

文章原創(chuàng)作者GuoLin 書籍推薦

郭林大神原創(chuàng)android 書籍:《第一行代碼 android》

淘寶鏈接: https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市苛坚,隨后出現(xiàn)的幾起案子比被,更是在濱河造成了極大的恐慌,老刑警劉巖泼舱,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件等缀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡娇昙,警方通過查閱死者的電腦和手機(jī)尺迂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冒掌,“玉大人噪裕,你說我怎么就攤上這事」珊粒” “怎么了膳音?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)铃诬。 經(jīng)常有香客問我祭陷,道長(zhǎng)苍凛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任兵志,我火速辦了婚禮醇蝴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘想罕。我一直安慰自己悠栓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布弧呐。 她就那樣靜靜地躺著闸迷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俘枫。 梳的紋絲不亂的頭發(fā)上腥沽,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音鸠蚪,去河邊找鬼今阳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛茅信,可吹牛的內(nèi)容都是我干的盾舌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蘸鲸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼妖谴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起酌摇,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤膝舅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后窑多,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仍稀,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年埂息,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了技潘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡千康,死狀恐怖享幽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吧秕,我是刑警寧澤琉闪,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站砸彬,受9級(jí)特大地震影響颠毙,放射性物質(zhì)發(fā)生泄漏斯入。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一蛀蜜、第九天 我趴在偏房一處隱蔽的房頂上張望刻两。 院中可真熱鬧,春花似錦滴某、人聲如沸磅摹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽户誓。三九已至,卻和暖如春幕侠,著一層夾襖步出監(jiān)牢的瞬間帝美,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工晤硕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悼潭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓舞箍,卻偏偏與公主長(zhǎng)得像舰褪,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子疏橄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容