使用eclipse 自帶的 DDMS 工具分析各線程的內(nèi)存使用情況,如下圖所示

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、微信平臺(tái)小程序開(kāi)發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了金塔免費(fèi)建站歡迎大家使用!
Heap視圖界面會(huì)定時(shí)刷新,在對(duì)應(yīng)用的不斷的操作過(guò)程中就可以看到內(nèi)存使用的變化。
怎樣判斷當(dāng)前進(jìn)程是否有內(nèi)存泄漏呢?
這里需要注意一個(gè)值:VM Heap頁(yè)面中部有一個(gè)data object選項(xiàng),即數(shù)據(jù)對(duì)象,也就是我們的程序中大量存在的類類型的對(duì)象。
在data object一行中有一列是“Total Size”,其值就是當(dāng)前進(jìn)程中所有Java數(shù)據(jù)對(duì)象的內(nèi)存總量,一般情況下,這個(gè)值的大小決定了是否會(huì)有內(nèi)存泄漏。如上圖中選中行所示。
可以據(jù)此判斷內(nèi)存有泄漏:
1) 不斷的操作當(dāng)前應(yīng)用,或者重復(fù)某一動(dòng)作,注意觀察data object的Total Size值。
2) 正常情況下Total Size值都會(huì)穩(wěn)定在一個(gè)有限的范圍內(nèi),也就是說(shuō)如果程序中的的代碼邏輯良好,
沒(méi)有創(chuàng)建的對(duì)象不被GC機(jī)制正常回收的情況,即便 我們不斷的操作生成很多對(duì)象,而在虛擬機(jī)不斷的進(jìn)行垃圾回收的過(guò)程中,這些對(duì)象都被正常回收了,內(nèi)存使用量會(huì)保持在一個(gè)比較穩(wěn)定的水平。
3) 如果代碼中存在對(duì)象引用沒(méi)有釋放的情況,則data object的Total Size值在每次GC后不會(huì)有明顯的回落,隨著操作次數(shù)的增多Total Size的值會(huì)越來(lái)越大。
正常情況下,一個(gè)虛擬機(jī)的進(jìn)程的內(nèi)存在64M, 如果內(nèi)存泄漏會(huì)發(fā)現(xiàn) Heap Size 在不斷的逼近 64M, 一旦達(dá)到這個(gè)值時(shí),就會(huì)出現(xiàn)退出應(yīng)用等情況。
發(fā)生內(nèi)存泄露,Total Size的值越來(lái)越大時(shí),按下“Dump HPROF file”按鈕,這個(gè)時(shí)候會(huì)提示設(shè)置hprof文件的保存路徑。保存后,可以對(duì)比log來(lái)分析是哪些操作造成了內(nèi)存泄漏。
內(nèi)存優(yōu)化就是對(duì)內(nèi)存問(wèn)題的一個(gè)預(yù)防和解決,做內(nèi)存優(yōu)化能讓應(yīng)用掛得少、活得好和活得久。
掛的少:
“掛”指的是 Crash,內(nèi)存問(wèn)題導(dǎo)致 Crash 的具體表現(xiàn)就是內(nèi)存溢出異常 OOM。
活得好:
活得好指的是使用流暢,Android 中造成界面卡頓的原因有很多種,其中一種就是由內(nèi)存問(wèn)題引起的。內(nèi)存問(wèn)題之所以會(huì)影響到界面流暢度,是因?yàn)槔厥眨℅C,Garbage Collection),在 GC 時(shí),所有線程都要停止,包括主線程,當(dāng) GC 和繪制界面的操作同時(shí)觸發(fā)時(shí),繪制的執(zhí)行就會(huì)被擱置,導(dǎo)致掉幀,也就是界面卡頓。
活得久:
活得久指的是我們的應(yīng)用在后臺(tái)運(yùn)行時(shí)不會(huì)被干掉。Android 會(huì)按照特定的機(jī)制清理進(jìn)程,清理進(jìn)程時(shí)優(yōu)先會(huì)考慮清理后臺(tái)進(jìn)程。清理進(jìn)程的機(jī)制就是LowMemoryKiller。在 Android 中不同的進(jìn)程有著不同的優(yōu)先級(jí),當(dāng)兩個(gè)進(jìn)程的優(yōu)先級(jí)相同時(shí),低殺會(huì)優(yōu)先考慮干掉消耗內(nèi)存更多的進(jìn)程。也就是如果我們應(yīng)用占用的內(nèi)存比其他應(yīng)用少,并且處于后臺(tái)時(shí),我們的應(yīng)用能在后臺(tái)活下來(lái),這也是內(nèi)存優(yōu)化為我們應(yīng)用帶來(lái)競(jìng)爭(zhēng)力的一個(gè)直接體現(xiàn)。
內(nèi)存占用是否越少越好?
當(dāng)系統(tǒng) 內(nèi)存充足 的時(shí)候,我們可以多用 一些獲得更好的性能。當(dāng)系統(tǒng) 內(nèi)存不足 的時(shí)候,我們希望可以做到 ”用時(shí)分配,及時(shí)釋放“。內(nèi)存優(yōu)化并不能一刀切。
我們都知道,應(yīng)用程序的內(nèi)存分配和垃圾回收都是由Android虛擬機(jī)完成的,在Android 5.0以下,使用的是Dalvik虛擬機(jī),5.0及以上,則使用的是ART虛擬機(jī)。
Android虛擬機(jī)Dalvik和ART
1、內(nèi)存區(qū)域劃分
詳細(xì)請(qǐng)看以下兩篇文章(建議全看):
java內(nèi)存四大區(qū)_JVM內(nèi)存區(qū)域劃分
Android 內(nèi)存機(jī)制
2、內(nèi)存回收
垃圾收集的標(biāo)記算法(找到垃圾):
垃圾收集算法(回收垃圾):
引用類型:強(qiáng)引用、軟引用、弱引用、虛引用
對(duì)象的有效性=可達(dá)性+引用類型
JAVA垃圾回收機(jī)制-史上最容易理解看這一篇就夠了
Android:玩轉(zhuǎn)垃圾回收機(jī)制與分代回收策略
android中還存在低殺機(jī)制,這種情況屬于系統(tǒng)整機(jī)內(nèi)存不足,直接把應(yīng)用進(jìn)程殺掉的情況。
Android后臺(tái)殺死系列:LowMemoryKiller原理
1、內(nèi)存溢出
系統(tǒng)會(huì)給每個(gè)App分配內(nèi)存空間也就是heap size值,當(dāng)app占用的內(nèi)存加上申請(qǐng)的內(nèi)存超過(guò)這個(gè)系統(tǒng)分配的內(nèi)存限額,最終導(dǎo)致OOM(OutOfMemory)使程序崩潰。
通過(guò)命令 getprop |grep dalvik.vm.heapsize 可以獲取系統(tǒng)允許的最大
注意:在設(shè)置了heapgrowthlimit的狀況下,單個(gè)進(jìn)程可用最大內(nèi)存為heapgrowthlimit值。在android開(kāi)發(fā)中,若是要使用大堆,須要在manifest中指定android:largeHeap為true,這樣dvm heap最大可達(dá)heapsize。
關(guān)于heapsize heapgrowthlimit
2、內(nèi)存泄漏
Android系統(tǒng)虛擬機(jī)的垃圾回收是通過(guò)虛擬機(jī)GC機(jī)制來(lái)實(shí)現(xiàn)的。GC會(huì)選擇一些還存活的對(duì)象作為內(nèi)存遍歷的根節(jié)點(diǎn)GC Roots,通過(guò)對(duì)GC Roots的可達(dá)性來(lái)判斷是否需要回收。內(nèi)存泄漏就是 在當(dāng)前應(yīng)用周期內(nèi)不再使用的對(duì)象被GC Roots引用,造成該對(duì)象無(wú)法被系統(tǒng)回收,以致該對(duì)象在堆中所占用的內(nèi)存單元無(wú)法被釋放而造成內(nèi)存空間浪費(fèi),使實(shí)際可使用內(nèi)存變小。簡(jiǎn)言之,就是 對(duì)象被持有導(dǎo)致無(wú)法釋放或不能按照對(duì)象正常的生命周期進(jìn)行釋放。
Android常見(jiàn)內(nèi)存泄漏匯總
3、內(nèi)存抖動(dòng)
指的是在短時(shí)間內(nèi)大量的新對(duì)象被實(shí)例化,運(yùn)行時(shí)可能無(wú)法承載這樣的內(nèi)存分配,在這種情況下就會(huì)導(dǎo)致垃圾回收事件被大量調(diào)用,影響到應(yīng)用程序的UI和整體性能,最終可能導(dǎo)致卡頓和OOM。
常見(jiàn)情況:在一些被頻繁調(diào)用的方法內(nèi)不斷地創(chuàng)建對(duì)象。例如在View 的onDraw方法內(nèi)new 一些新的對(duì)象。
注意內(nèi)存抖動(dòng)也會(huì)導(dǎo)致 OOM,主要原因有如下兩點(diǎn):
1、Android Studio Profiler
作用
優(yōu)點(diǎn)
內(nèi)存抖動(dòng)問(wèn)題處理實(shí)戰(zhàn)
理解內(nèi)存抖動(dòng)的概念的話,我們就能明白只要能找到抖動(dòng)過(guò)程中所產(chǎn)生的對(duì)象及其調(diào)用棧,我們就能解決問(wèn)題,剛好Android Studio 的Porfiler里面的Memory工具就能幫我們記錄下我們操作過(guò)程中或靜止界面所產(chǎn)生的新對(duì)象,并且能清晰看到這些對(duì)象的調(diào)用棧。
選擇Profile 中 的Memory ,選擇 Record Java/Kotlin allocations,再點(diǎn)擊Record開(kāi)始記錄, Record Java/Kotlin allocations 選項(xiàng)會(huì)記錄下新增的對(duì)象。
操作完成之后,點(diǎn)擊如圖所示的紅腦按鈕,停止記錄。
停止記錄后,我們就可以排序(點(diǎn)擊 Allocations可以排序)看看哪些對(duì)象或基本類型在短時(shí)間被頻繁創(chuàng)建多個(gè),點(diǎn)擊這些新增的對(duì)象就可以看到它的完成的調(diào)用鏈了,進(jìn)而就找找到導(dǎo)致內(nèi)存抖動(dòng)的地方在哪里了。
2、利用DDMS 和 MAT(Memory Analyzer tool)來(lái)分析內(nèi)存泄漏
我們利用工具進(jìn)行內(nèi)存泄漏分析主要是用對(duì)比法:
a.先打開(kāi)正常界面,不做任何操作,先抓取一開(kāi)始的堆文件。
b.一頓胡亂操作,回到原來(lái)操作前的界面。主動(dòng)觸發(fā)一兩次GC,過(guò)10秒再抓取第二次堆文件。
c.通過(guò)工具對(duì)比,獲取胡亂操作后新增的對(duì)象,然后分析這些新增的對(duì)象。
DDMS作用:抓取堆文件,主動(dòng)觸發(fā)GC。(其實(shí)也是可以用Android Studio 的Profile里面的Memory工具來(lái)抓取堆文件的,但是我這邊在利用Profile 主動(dòng)觸發(fā)gc 的時(shí)候會(huì)導(dǎo)致程序奔潰,也不知道是不是手機(jī)的問(wèn)題,所以沒(méi)用Android Studio的Profiler)
MAT作用:對(duì)堆文件進(jìn)行對(duì)比,找到多出的對(duì)象,找到對(duì)象的強(qiáng)引用調(diào)用鏈。
以下是詳細(xì)的過(guò)程:
步驟1.打開(kāi)DDMS,選擇需要調(diào)試的應(yīng)用,打開(kāi)初始界面,點(diǎn)擊下圖的圖標(biāo)(Dump Hprof File)先獲取一次堆文件。
步驟2.對(duì)應(yīng)用隨便操作后,回到一開(kāi)始的界面,先多觸發(fā)幾次GC ,點(diǎn)擊下圖的圖標(biāo)(Cause Gc)來(lái)主動(dòng)觸發(fā)GC,然后再次點(diǎn)擊 Dump Hprof File 圖標(biāo)來(lái)獲取堆文件。
步驟3.通過(guò)Android Studio Profile 或者 DDMS dump 的堆文件無(wú)法在MAT 打開(kāi),需要借助android sdk包下的一個(gè)工具h(yuǎn)prof-conv.exe來(lái)轉(zhuǎn)換。
格式為 hprof-conv 舊文件路徑名 要轉(zhuǎn)換的名稱;
例如:hprof-conv 2022-04-13_17-54-40_827.hprof change.hprof
步驟4.把兩份堆文件導(dǎo)入MAT,然后選擇其中第二次獲取的堆文件,點(diǎn)擊 如圖所示的 Histogram查看。
步驟5.點(diǎn)擊下圖圖標(biāo),Compare To Another Heap Dump ,選擇另一份堆文件。
6.會(huì)得出下圖所示的 Hitogram 展示,我們主要看Objects 這一列。 如下圖所示 “+ 2” 則代表前面兩份堆文件對(duì)比,這個(gè)對(duì)象多了兩個(gè),我們主要就是要分析這些多了出來(lái),沒(méi)有被回收的對(duì)象。
7.加入我們從增加的對(duì)象中,看到了MainActivity ,則需要從一開(kāi)始打開(kāi)的Hitogram 展示里面找到這個(gè)對(duì)象的調(diào)用棧。如下圖所示,搜索MainActivity
8.看到下圖所示解雇,然后鼠標(biāo)右鍵點(diǎn)擊下圖紅色圈圈著的MainActivity ,選擇 Merger Shortest Paths to Gc Roots ,再選擇 exclude all phantom/weak/soft etc.references ,就可以看到這個(gè)MainActivity 對(duì)象的強(qiáng)引用鏈,至此我們就可以找到MainActivity對(duì)象是被什么引用導(dǎo)致無(wú)法回收了。
3、內(nèi)存泄露檢測(cè)神器之LeakCanary(線下集成)
自行學(xué)習(xí)了解,接入簡(jiǎn)單,使用簡(jiǎn)單,基本可以解決大部分內(nèi)存泄漏問(wèn)題。
github地址 :
學(xué)習(xí)地址 :
針對(duì)內(nèi)存抖動(dòng)的建議:
針對(duì)內(nèi)存泄漏問(wèn)題的建議:
針對(duì)內(nèi)存溢出問(wèn)題的建議(主要就是要減少內(nèi)存占用):
建議參考:
深入探索 Android 內(nèi)存優(yōu)化(煉獄級(jí)別)
對(duì)于 優(yōu)化的大方向,我們應(yīng)該優(yōu)先去做見(jiàn)效快的地方,主要有以下三部分:內(nèi)存泄漏、內(nèi)存抖動(dòng)、Bitmap。完善監(jiān)控機(jī)制也是我們的重點(diǎn),能幫助我們對(duì)內(nèi)存問(wèn)題快速分析和處理。
參考:
深入探索 Android 內(nèi)存優(yōu)化(煉獄級(jí)別)
依賴庫(kù)即可,重點(diǎn)在分析工具和分析方法:
debugImplementation'com.squareup.leakcanary:leakcanary-android:2.8.1'
分析工具:MAT 、AndroidStudioProfiler?和?自帶分析工具;
這里先看一下Leaking的狀態(tài)(YES、NO、UNKNOWN),NO表示沒(méi)泄露、YES表示出現(xiàn)泄漏、UNKNOW表示可能泄漏。
具體學(xué)習(xí)資料: 學(xué)習(xí)資料
首先了解下Android中最重要的四大內(nèi)存指標(biāo)的概念
我們主要使用USS和PSS來(lái)衡量進(jìn)程的內(nèi)存使用情況
dumpsys meminfo命令展示的是系統(tǒng)整體內(nèi)存情況,內(nèi)存項(xiàng)按進(jìn)程進(jìn)行分類
查看單個(gè)進(jìn)程的內(nèi)存信息,命令如下
adb shell dumpsys meminfo [pid | packageName]
Objects中Views、Activities、AppContexts的異常可以判斷有內(nèi)存泄露,比如剛退出應(yīng)用,查看Activites是否為0,如果不為0,則有Activity沒(méi)有銷毀。
具體用法直接參考大佬的資源即可,不贅述。
android studio 中Memory Profile的用法
接入LeakCanary,監(jiān)控所有Activity和Fragment的釋放,App所有功能跑一遍,觀察是否有抓到內(nèi)存泄露的地方,分析引用鏈找到并解決問(wèn)題,如此反復(fù),直到LeakCanary檢查不到內(nèi)存泄露。
adb shell dumpsys meminfo命令查看退出界面后Objects的Views和Activities數(shù)目,特別是退出App后數(shù)目為否為0。
打開(kāi)Android Studio Memory Profiler,反復(fù)打開(kāi)關(guān)閉頁(yè)面多次,點(diǎn)擊GC,如果內(nèi)存沒(méi)有恢復(fù)到之前的數(shù)值,則可能發(fā)生了內(nèi)存泄露。再點(diǎn)擊Profiler的垃圾桶圖標(biāo)旁的heap dump按鈕查看當(dāng)面內(nèi)存堆棧情況,按包名找到當(dāng)前測(cè)試的Activity,如果存在多份實(shí)例,則很可能發(fā)生了內(nèi)存泄露。
Android內(nèi)存優(yōu)化一:java垃圾回收機(jī)制
Android內(nèi)存優(yōu)化二:內(nèi)存泄漏
Android內(nèi)存優(yōu)化三:內(nèi)存泄漏檢測(cè)與監(jiān)控
Android內(nèi)存優(yōu)化四:OOM
Android內(nèi)存優(yōu)化五:Bitmap優(yōu)化
Memory Profiler 是 Profiler 中的其中一個(gè)版塊,Profiler 是 Android Studio 為我們提供的性能分析工具,使用 Profiler 能分析應(yīng)用的 CPU、內(nèi)存、網(wǎng)絡(luò)以及電量的使用情況。
進(jìn)入了 Memory Profiler 界面。
點(diǎn)擊 Record 按鈕后,Profiler 會(huì)為我們記錄一段時(shí)間內(nèi)的內(nèi)存分配情況。
在內(nèi)存分配面板中,通過(guò)拖動(dòng)時(shí)間線來(lái)查看一段時(shí)間內(nèi)的內(nèi)存分配情況
通過(guò)搜索類或者報(bào)名的方式查看對(duì)象的使用情況
使用Memory Profiler 分析內(nèi)存可以查看官網(wǎng): 使用內(nèi)存性能分析器查看應(yīng)用的內(nèi)存使用情況
對(duì)于內(nèi)存泄漏問(wèn)題,Memory Profiler 只能提供一個(gè)簡(jiǎn)單的分析,不能夠確認(rèn)具體發(fā)生問(wèn)題的地方。
而 MAT 就可以幫我們做到這一點(diǎn),它是一款功能強(qiáng)大的 Java 堆內(nèi)存分析工具,可以用于查找內(nèi)存泄漏以及查看內(nèi)存消耗情況。
as 生成hprof文件無(wú)法被mat識(shí)別,需要進(jìn)行轉(zhuǎn)換
使用hprof-conv進(jìn)行轉(zhuǎn)換,hprof-conv位于sdk\platform-tools
ps:as導(dǎo)出hprof前最好先gc幾次,可排除一些干擾
Histogram 可以列出內(nèi)存中的對(duì)象,對(duì)象的個(gè)數(shù)以及大小; Dominator Tree 可以列出那個(gè)線程,以及線程下面的那些對(duì)象占用的空間; Top consumers 通過(guò)圖形列出最大的object; Leak Suspects 通過(guò)MA自動(dòng)分析泄漏的原因。
Shallow Heap就是對(duì)象本身占用內(nèi)存的大小,不包含其引用的對(duì)象內(nèi)存,實(shí)際分析中作用不大。常規(guī)對(duì)象(非數(shù)組)的ShallowSize由其成員變量的數(shù)量和類型決定。數(shù)組的shallow size有數(shù)組元素的類型(對(duì)象類型、基本類型)和數(shù)組長(zhǎng)度決定。對(duì)象成員都是些引用,真正的內(nèi)存都在堆上,看起來(lái)是一堆原生的byte[], char[], int[],對(duì)象本身的內(nèi)存都很小。
Retained Heap值的計(jì)算方式是將Retained Set(當(dāng)該對(duì)象被回收時(shí)那些將被GC回收的對(duì)象集合)中的所有對(duì)象大小疊加。或者說(shuō),因?yàn)閄被釋放,導(dǎo)致其它所有被釋放對(duì)象(包括被遞歸釋放的)所占的heap大小。
Path To GC Roots - exclude all phantim/weak/soft etc. references:查看這個(gè)對(duì)象的GC Root,不包含虛、弱引用、軟引用,剩下的就是強(qiáng)引用。從GC上說(shuō),除了強(qiáng)引用外,其他的引用在JVM需要的情況下是都可以 被GC掉的,如果一個(gè)對(duì)象始終無(wú)法被GC,就是因?yàn)閺?qiáng)引用的存在,從而導(dǎo)致在GC的過(guò)程中一直得不到回收,因此就內(nèi)存泄漏了。
List objects - with incoming references:查看這個(gè)對(duì)象持有的外部對(duì)象引用
List objects - with outcoming references:查看這個(gè)對(duì)象被哪些外部對(duì)象引用
使用對(duì)象查詢語(yǔ)言可以快速定位發(fā)生泄漏的Activity及Fragment
使用 MAT 來(lái)分析內(nèi)存問(wèn)題,效率比較低,為了能迅速發(fā)現(xiàn)內(nèi)存泄漏,Square 公司基于 MAT 開(kāi)源了 LeakCanary ,LeakCanary 是一個(gè)內(nèi)存泄漏檢測(cè)框架。
集成LeakCanary后,可以在桌面看到 LeakCanary 用于分析內(nèi)存泄漏的應(yīng)用。
當(dāng)發(fā)生泄漏,會(huì)為我們生成一個(gè)泄漏信息概覽頁(yè),可以看到泄漏引用鏈的詳情。
LeakCanary 會(huì)解析 hprof 文件,并且找出導(dǎo)致 GC 無(wú)法回收實(shí)例的引用鏈,這也就是泄漏蹤跡(Leak Trace)。
泄漏蹤跡也叫最短強(qiáng)引用路徑,這個(gè)路徑是 GC Roots 到實(shí)例的路徑。
LeakCanary 存在幾個(gè)問(wèn)題,不同用于線上監(jiān)控功能
線上監(jiān)控需要做的,就是解決以上幾個(gè)問(wèn)題。
各大廠都有開(kāi)發(fā)線上監(jiān)控方案,比如快手的 KOOM ,美團(tuán)的 Probe ,字節(jié)的 Liko
快手自研OOM解決方案KOOM今日宣布開(kāi)源
總結(jié)一下幾點(diǎn):
通過(guò)無(wú)性能損耗的 內(nèi)存閾值監(jiān)控 來(lái)觸發(fā)鏡像采集。將對(duì)象是否泄漏的判斷延遲到了解析時(shí)
利用系統(tǒng)內(nèi)核COW( Copy-on-write ,寫時(shí)復(fù)制)機(jī)制,每次dump內(nèi)存鏡像前先暫停虛擬機(jī),然后fork子進(jìn)程來(lái)執(zhí)行dump操作,父進(jìn)程在fork成功后立刻恢復(fù)虛擬機(jī)運(yùn)行,整個(gè)過(guò)程對(duì)于父進(jìn)程來(lái)講總耗時(shí)只有幾毫秒,對(duì)用戶完全沒(méi)有影響。
當(dāng)前文章:android分析內(nèi)存,Android 內(nèi)存管理
文章轉(zhuǎn)載:http://chinadenli.net/article1/dseodod.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、企業(yè)建站、小程序開(kāi)發(fā)、域名注冊(cè)、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)