網(wǎng)站首頁 行業(yè)快訊 > 正文
安卓怎么清理內(nèi)存(Android優(yōu)化———內(nèi)存優(yōu)化)
Java虛擬機Java內(nèi)存模型虛擬機棧(線程私有):局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息
堆(線程共享):實例對象
方法區(qū)(線程共享):類信息,常量,即時編譯器編譯后的代碼
程序計數(shù)器(線程私有):字節(jié)碼行號指示器,記錄當前線程執(zhí)行到多少行
本地方法棧(線程私有):和虛擬機棧類似,兩者的區(qū)別就是虛擬機棧是為虛擬機執(zhí)行java方法服務,本地方法棧為虛擬機執(zhí)行native方法服務 。
程序計數(shù)器線程計數(shù)器中如果正在執(zhí)行java方法,計數(shù)器記錄的是當前指令的地址,
如果是Native方法,計數(shù)器記錄為空
堆堆內(nèi)存 = 新生代(1) + 老年代(2)
新生代:復制算法
老年代:標記整理算法
方法區(qū)也叫“永久代”,8以后將方法區(qū)去除了,將方法區(qū)移動到直接內(nèi)存
內(nèi)存回收主要考慮堆區(qū)和方法區(qū)的回收,其他部分會根據(jù)線程的產(chǎn)生和消亡
個版本區(qū)別6:運行常量池在方法區(qū)
7:運行常量池在堆中
8:刪除方法區(qū),引入直接內(nèi)存,元空間概念,方法區(qū)中的靜態(tài)變量被轉(zhuǎn)移到堆中,只有class元數(shù)據(jù)在元空間。
堆中的老年代和方法區(qū)(永久代)是綁定的,無論哪一方滿了,都會觸發(fā)雙方的GC回收
問題:堆和棧的區(qū)別:棧:基本數(shù)據(jù)類型變量(int、short、long、byte、float、double、boolean、char)以及對象的引用變量堆:存儲java對象堆中的對象對所有線程可見,棧內(nèi)存只屬于一個線程堆的內(nèi)存空間遠遠大于棧
為什么刪除方法區(qū)?啟動大小固定,很難調(diào)優(yōu),容易發(fā)生OOM元空間在本地內(nèi)存中分配,本地內(nèi)存足夠就不會溢出
GC垃圾回收判斷對象是否存活引用計數(shù)算法(缺點:循環(huán)引用,技數(shù)永遠不為0)
可達性算法(二叉樹中向下搜索,不存在引用鏈則對象不可用)
回收算法標記清除算法:標記完后對對象進行回收,使用在老年代缺點:效率不高,標記和清除效率不高差生大量碎片空間,導致空間浪費
復制算法:將可用對象復制到新的連續(xù)空間,刪除之前的空間缺點:浪費50%的內(nèi)存,復制長生存期的對象效率低下,所以該算法使用在新生代
標記整理算法:前期使用標記清除算法,后續(xù)使用整理算法,使對象排列稱聯(lián)系空間,使用在老年代
分代收集算法:對數(shù)據(jù)進行分代,每一代執(zhí)行不同的回收算法
年輕代分為eden、s0、s1區(qū),分別為8:1:1,年輕代和老年代為1:2
元空間的gc:元空間中的類加載器存活,則元空間中元數(shù)據(jù)也存活
四大引用介紹簡述Minor GC : 清理年輕代
Major GC : 清理老年代Full GC : 清理整個堆空間,包括年輕代和永久代
強引用:Strong Reference,通常使用的對象方式,gc不會回收
軟引用:SoftReference,當內(nèi)存不足時進行回收
弱引用:WeakReference,下一次gc時回收
虛引用:PhantomReference,任何時候可回收
在內(nèi)存泄露問題處理上,使用最多的是弱引用,許多源碼、框架都是用
eg:
ThreadLocalMap中存儲以ThreadLocal的弱引用為鍵,具體內(nèi)容為value
Glide中緩存使用activeResource,存儲的是圖片的弱引用
解決Handler的內(nèi)存泄漏使用弱引用
Reference理解所有的引用都是繼承自Reference,以下以WeakReference為例:
publicclassWeakReference<T>extendsReference<T>{/***Createsanewweakreferencethatreferstothegivenobject.Thenew*referenceisnotregisteredwithanyqueue.**@paramreferentobjectthenewweakreferencewillreferto*/publicWeakReference(Treferent){super(referent);}/***Createsanewweakreferencethatreferstothegivenobjectandis*registeredwiththegivenqueue.**@paramreferentobjectthenewweakreferencewillreferto*@paramqthequeuewithwhichthereferenceistoberegistered,*or<tt>null</tt>ifregistrationisnotrequired*/publicWeakReference(Treferent,ReferenceQueue<?superT>q){super(referent,q);}}
其中存在兩種構(gòu)造方法,區(qū)別在于是否傳入引用隊列,如果不傳入引用隊列,說明只存在一種引用,不需要引用隊列成鏈存儲
publicabstractclassReference<T>{privatestaticbooleandisableIntrinsic=false;privatestaticbooleanslowPathEnabled=false;//引用的對象,由垃圾回收器控制其引用volatileTreferent;/*TreatedspeciallybyGC*/finalReferenceQueue<?superT>queue;ReferencequeueNext;Reference<?>pendingNext;publicTget(){returngetReferent();}@FastNativeprivatefinalnativeTgetReferent();publicvoidclear(){clearReferent();}@FastNativenativevoidclearReferent();publicbooleanisEnqueued(){//Contrarytowhatthedocumentationsays,thismethodreturnsfalse//afterthisreferenceobjecthasbeenremovedfromitsqueue//(b/26647823).ReferenceQueue.isEnqueuedpreservesthishistorically//incorrectbehavior.returnqueue!=null&&queue.isEnqueued(this);}publicbooleanenqueue(){returnqueue!=null&&queue.enqueue(this);}/*--Constructors--*/Reference(Treferent){this(referent,null);}Reference(Treferent,ReferenceQueue<?superT>queue){this.referent=referent;this.queue=queue;}}
抽象類很簡短,可以看出一個關(guān)鍵點,Reference是一個節(jié)點,保存next的引用,方法調(diào)用都是使用ReferenceQueue方法,直接進入:
privateReference<?extendsT>head=null;privateReference<?extendsT>tail=null;booleanenqueue(Reference<?extendsT>reference){synchronized(lock){if(enqueueLocked(reference)){lock.notifyAll();returntrue;}returnfalse;}}privatebooleanenqueueLocked(Reference<?extendsT>r){...if(rinstanceofCleaner){Cleanercl=(sun.misc.Cleaner)r;cl.clean();r.queueNext=sQueueNextUnenqueued;returntrue;}if(tail==null){head=r;}else{tail.queueNext=r;}tail=r;tail.queueNext=r;returntrue;}
入隊方法中,
使用synchronized添加鎖,入隊結(jié)束后釋放鎖,在ReferenceQueue中并不是標準的隊列,使用的是Reference節(jié)點成鏈,行成單鏈表,類似于MessageQueue.
如果是Cleaner類,創(chuàng)建一個虛引用節(jié)點,即不如隊。Cleaner是用來釋放非堆內(nèi)存,所以做特殊處理
SoftReference
>publicclassSoftReference<T>extendsReference<T>{//時間戳,由gc更新staticprivatelongclock;privatelongtimestamp;publicSoftReference(Treferent){super(referent);this.timestamp=clock;}/***Createsanewsoftreferencethatreferstothegivenobjectandis*registeredwiththegivenqueue.**@paramreferentobjectthenewsoftreferencewillreferto*@paramqthequeuewithwhichthereferenceistoberegistered,*or<tt>null</tt>ifregistrationisnotrequired**/publicSoftReference(Treferent,ReferenceQueue<?superT>q){super(referent,q);this.timestamp=clock;}publicTget(){To=super.get();if(o!=null&&this.timestamp!=clock)this.timestamp=clock;returno;}}
由gc管理時間戳
clock:上一次gc時間
timestamp:訪問get時最近一次的gc時間
回收條件為:clock - timestamp <= free_heap * ms_per_mb
free_heep為堆空間空閑大小
ms_per_mb是保留軟引用時間/MB
PhantomReference
publicclassPhantomReference<T>extendsReference<T>{publicTget(){returnnull;}publicPhantomReference(Treferent,ReferenceQueue<?superT>q){super(referent,q);}}
虛引用的get方法返回null,不做gc保留
虛引用通過構(gòu)造方法可以查看是持有對象引用的
總結(jié):所有引用都是繼承自Reference基類的,該類是一個鏈表節(jié)點,ReferenceQueue通過這點形成單鏈表,稱之為隊列,進行引用管理,所有引用都可以通過Reference的isEnqueue方法判斷引用是否存在。
FinalizerReference理解java堆中創(chuàng)建對象時,如果java類定義了finalize方法,就會新建一個FinalizerReference類,指向這個新建的對象
內(nèi)存問題內(nèi)存泄漏:內(nèi)存沒有按照預期在gc時回收
內(nèi)存溢出:內(nèi)存大小超出指定大小,導致OOM
內(nèi)存抖動:短時間創(chuàng)建大量內(nèi)存對象,然后回收,導致內(nèi)存發(fā)生鋸齒形抖動,內(nèi)存空間不連續(xù)加上碎片會導致更大的空間,最終OOM
內(nèi)存優(yōu)化意義減少OOM,提高系統(tǒng)穩(wěn)定性
減少卡頓,提高流暢度
減少內(nèi)存占用,提高應用存活率
減少異常發(fā)生和代碼邏輯隱患
Android內(nèi)存泄漏常見內(nèi)存泄漏匿名內(nèi)部類持有外部類引用,導致外部類內(nèi)存泄漏(Handler)
單例傳入Context導致調(diào)用單例方無法被回收。
非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實例
注冊與反注冊
資源對象關(guān)閉
集和及時清理
內(nèi)存泄漏檢測Profiler,Memory Analyzer(MAT)
Android studio自帶內(nèi)存、cpu、網(wǎng)絡的變化,可以根據(jù)內(nèi)存變化做具體分析
LeakCanary
框架集成,自動檢測內(nèi)存泄漏,生成app,提供內(nèi)存泄漏棧堆情況
原理:綁定生命周期,對Activity和Fragment來說,在onDestory時將對象放入弱引用隊列進行存儲,觸發(fā)gc后,如果還存在,則發(fā)生內(nèi)存泄漏
StrictMode(很少用)
一款比較老的工具,ThreadPolicy可以檢測主線程是否網(wǎng)絡訪問,是否讀寫。VMPolicy檢測內(nèi)存,Activity,F(xiàn)ragment是否泄漏,資源是否正確關(guān)閉
內(nèi)存優(yōu)化空間不必要的自動裝箱
自動裝箱就是將基礎(chǔ)數(shù)據(jù)類型轉(zhuǎn)化為對應的復雜類型,在HashMap的增刪改查中充滿了自動裝箱問題,所以盡量避免這中問題,如將HashMap替換為SparseArray和ArrayMap
內(nèi)存復用
資源復用:通用字符串,顏色,布局
視圖復用:類似于RecyclerView的優(yōu)化復用
對象池:創(chuàng)建對象池,不用重復創(chuàng)建對象,類似于線程池,messae享元模式
Bitmap對象復用:使用inBitmap屬性可以告知Bitmap解碼器嘗試使用已經(jīng)存在的內(nèi)存區(qū)域,新解碼的bitmap會嘗試使用之前那張bitmap在heap中占據(jù)的pixel data內(nèi)存區(qū)域。
在App可用內(nèi)存過低時主動釋放內(nèi)存在App退到后臺內(nèi)存緊張即將被Kill掉時選擇重寫Application中 onTrimMemory/onLowMemory 方法去釋放掉圖片緩存、靜態(tài)緩存來自保。
其他場景優(yōu)化item被回收不可見時釋放掉對圖片的引用ListView:因此每次item被回收后再次利用都會重新綁定數(shù)據(jù),只需在ImageView onDetachFromWindow的時候釋放掉圖片引用即可。RecyclerView:因為被回收不可見時第一選擇是放進mCacheView中,這里item被復用并不會只需bindViewHolder來重新綁定數(shù)據(jù),只有被回收進mRecyclePool中后拿出來復用才會重新綁定數(shù)據(jù),因此重寫Recycler.Adapter中的onViewRecycled()方法來使item被回收進RecyclePool的時候去釋放圖片引用。如果使用字符串拼接,盡量使用StringBuilder、StringBuffer(內(nèi)存抖動)自定義view減少onDraw的耗時和執(zhí)行次數(shù)盡量使用靜態(tài)內(nèi)部類盡量使用基礎(chǔ)數(shù)據(jù)類型合適的時候使用軟/弱引用
線上監(jiān)控方案常規(guī)監(jiān)測當內(nèi)存使用超過80%,使用Debug.dumpHprofData(String fileName)
獲取dump文件回傳至服務器,而后手動分析LeakCanary集成并帶到線上Probe線上監(jiān)測工具
LeakInspector
ResourceCanary
最后小編在網(wǎng)上收集了一些Android 開發(fā)相關(guān)的學習文檔、面試題、Android 核心筆記等等文檔,希望能幫助到大家學習提升,如有需要參考的可以直接私信我領(lǐng)取哦
版權(quán)說明: 本文由用戶上傳,如有侵權(quán)請聯(lián)系刪除!
猜你喜歡:
- 2022-09-20 男人惡心是什么病的前兆(惡心是什么病的前兆)
- 2022-09-20 山東財經(jīng)大學東方學院考研率怎么樣(山東財經(jīng)大學考研率是多少)
- 2022-09-20 廣西最早的大學叫什么大學(在桂林設(shè)立的廣西最早的大學是哪所大學)
- 2022-09-20 小兒肺炎有5個常見癥狀嗎(小兒肺炎有5個常見癥狀)
- 2022-09-20 m是哪個服裝品牌的標志(標志為M的衣服是什么牌子的)
- 2022-09-20 什么叫正比例什么叫反比例舉例說明(什么叫反比例,舉個例子說明,)
- 2022-09-20 一包煙要多少根煙絲(一包煙要多少根)
- 2022-09-20 男人吃櫻桃對身體有什么好處(男人吃櫻桃有什么好處)
最新文章:
- 2023-07-02 怎樣挑選新鮮的豬肝?(怎么挑選新鮮豬肝 挑選新鮮豬肝的小技巧)
- 2023-07-02 木地板都有哪些種類(木地板的種類有哪些)
- 2023-07-02 白蠟木家具的優(yōu)缺點(松木家具的優(yōu)缺點)
- 2023-07-02 怎么清洗窗簾布上的污垢(怎么清洗窗簾)
- 2023-07-02 世界上最可愛的小倉鼠的樣子(可愛小倉鼠的種類)
- 2023-07-02 小貓拉不出來屎怎么辦(小貓拉不出屎怎么辦)
- 2023-07-02 新飛小冰箱耗電量一天多少度(小冰箱耗電量一天多少度)
- 2023-07-02 公司注銷工業(yè)房產(chǎn)怎么辦手續(xù)(公司注銷工業(yè)房產(chǎn)怎么辦)
- 2023-07-02 鳳凰層到底好還是不好(鳳凰層是哪一層)
- 2023-07-02 馬桶寬度空間留多少(馬桶兩邊的空間大小是多少)
- 2023-07-02 如何訓練貓咪小便(如何訓練貓大小便)
- 2023-07-02 衛(wèi)生間吊頂防潮層做法圖集(衛(wèi)生間吊頂方法是什么)
- 2023-07-02 狗狗為什么總是流口水怎么辦(狗狗為什么愛流口水)
- 2023-07-02 臥室窗戶漏水由誰負責維修(臥室窗戶漏風怎么辦)
- 2023-07-02 世界名貓大全(世界名貓你知道幾種)
- 2023-07-02 applewatchseries7和6對比(apple watch series 7和6的區(qū)別)