<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發

      導航

      性能優化2--內存優化

      a.Bitmap.recycle(),Cursor.close,inputStream.close()

      b.大量加載Bitmap時,根據View大小加載Bitmap,合理選擇inSampleSize,RGB_565編碼方式;使用LruCache緩存

      c.使用 靜態內部類+WeakReference 代替內部類,如Handler、線程、AsyncTask

      d.使用線程池管理線程,避免線程的新建

      e.使用單例持有Context,需要記得釋放,或者使用全局上下文

      f.靜態集合對象注意釋放

      像HashMap、Vector等的使用最容易出現內存泄露,這些靜態變量的生命周期和應用程序一致,他們所引用的所有的對象Object也不能被釋放,因為他們也將一直被Vector等引用著。
      例如
      Static Vector v = new Vector(10);
      for (int i = 1; i<100; i++)
      {
          Object o = new Object();
          v.add(o);
          o = null;
      }
      在這個例子中,循環申請Object 對象,并將所申請的對象放入一個Vector 中,如果僅僅釋放引用本身(o=null),那么Vector 仍然引用該對象,所以這個對象對GC 來說是不可回收的。因此,如果對象加入到Vector 后,還必須從Vector 中刪除,最簡單的方法就是將Vector對象設置為null。 

      g.屬性動畫造成內存泄露

      h.使用webView,在Activity.onDestory需要移除和銷毀,webView.removeAllViews()和webView.destory()

      i.頻繁字符串拼接用StringBuilder

      j.ArrayMap SparseArray替代HashMap

      一.內存管理

      1.內存分配

      方法區:方法區存放的是類信息、常量、靜態變量,所有線程共享區域。
      虛擬機棧:每個方法在執行的同時都會創建一個棧幀(Stack Frame)用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息,線程私有區域。
      本地方法棧:與虛擬機棧類似,區別是虛擬機棧為虛擬機執行Java方法服務,本地方法棧為虛擬機使用到的Native方法服務。
      :JVM管理的內存中最大的一塊,所有線程共享;用來存放對象實例,幾乎所有的對象實例都在堆上分配內存;此區域也是垃圾回收器(Garbage Collection)主要的作用區域,內存泄漏就發生在這個區域。
      程序計數器:可看做是當前線程所執行的字節碼的行號指示器;如果線程在執行Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令地址;如果執行的是Native方法,這個計數器的值為空(Undefined)。
      備注:
      有一種習慣說法:把Java的內存區域分為堆內存(Heap)和棧內存(Stack),Stack訪問快,Heap訪問慢,Stack中保存的是對象的引用(指針),Heap中保存的是對象的實例。實際上這種說法是籠統、粗糙的,此處所說的Stack僅僅是虛擬機棧中的局部變量表部分。虛擬機棧與JVM運行時數據區涵蓋的都比此種說法多。

      2.內存回收

      2.1標記-清除算法
      最基礎的收集算法:分為“標記”和“清除”兩個階段,首先,標記出所有需要回收的對象,然后統一回收所有被標記的對象。
      這種方法有兩個不足點:
      效率問題,標記和清除兩個過程的效率都不高;
      空間問題,標記清除之后會產生大量的不連續的內存碎片。

       2.2復制算法
      將內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊,當這一塊內存將用完了,就將還存活著的對象復制到另一塊內存上面,然后再把已使用過的內存空間一次清理掉。
      這種方法的特點:
      優點:實現簡單,運行高效;每次都是對整個半區進行內存回收,內存分配時也不需要考慮內存碎片等情況,只要移動堆頂指針,按順序分配內存即可;
      缺點:粗暴的將內存縮小為原來的一半,代價實在有點高。

       

      2.3標記-整理算法
      先標記需要回收的對象(標記過程與“標記-清除”算法一樣),然后把所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存。
      這種方法的特點:
      避免了內存碎片;
      避免了“復制”算法50%的空間浪費;
      主要針對對象存活率高的老年代。


      2.4分代收集算法
        根據對象的存活周期的不同將內存劃分為幾塊,一般是把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點采用最適當的收集算法。在新生代中,每次垃圾收集時都會發現有大量對象死去,只有少量存活,那就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行分配擔保,就必須使用標記—清除算法或標記—整理算法來進行回收。

      3、對象是否回收的依據

      3.1引用計數算法
        給對象中添加一個引用計數器,每當有一個地方引用該對象時,計數器值加1;引用失效時,計數器值減1;任意時刻計數器為0的對象就是不可能再被使用的,表示該對象不存在引用關系。
      這種方法的特點:
      優點:實現簡單,判定效率也很高;
      缺點:難以解決對象之間相互循環引用導致計數器值不等于0的問題。
      3.2可達性分析算法
        以一系列成為“GC Roots”的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈相連(GC Roots到這個對象不可達),則證明此對象是不可用的。
       
      4、Android的內存管理
        Android系統的ART和Dalvik虛擬機扮演了常規的內存垃圾自動回收的角色, 使用paging 和 memory-mapping來管理內存,這意味著不管是因為創建對象還是使用使用內存頁面造成的任何被修改的內存,都會一直存在于內存中,App唯一釋放內存的方法就是釋放App持有的對象引用,使GC可以回收。
      4.1內存回收
          在Android的高級系統版本里面針對Heap空間有一個Generational Heap Memory的模型,最近分配的對象會存放在Young Generation區域,當這個對象在這個區域停留的時間達到一定程度,它會被移動到Old Generation,最后累積一定時間再移動到Permanent Generation區域。系統會根據內存中不同的內存數據類型分別執行不同的gc操作。例如,剛分配到Young Generation區域的對象通常更容易被銷毀回收,同時在Young Generation區域的gc操作速度會比Old Generation區域的gc操作速度更快。
      View Code

      4.2共享內存

          Android應用的進程都是從一個叫做Zygote的進程fork出來的。Zygote進程在系統啟動并且載入通用的framework的代碼與資源之后開始啟動。為了啟動一個新的程序進程,系統會fork Zygote進程生成一個新的進程,然后在新的進程中加載并運行應用程序的代碼。這使得大多數的RAM pages被用來分配給framework的代碼,同時使得RAM資源能夠在應用的所有進程之間進行共享。
      大多數static的數據被mmapped到一個進程中。這不僅僅使得同樣的數據能夠在進程間進行共享,而且使得它能夠在需要的時候被paged out。常見的static數據包括Dalvik Code,app resources,so文件等。
      大多數情況下,Android通過顯式的分配共享內存區域(例如ashmem或者gralloc)來實現動態RAM區域能夠在不同進程之間進行共享的機制。例如,Window Surface在App與Screen Compositor之間使用共享的內存,Cursor Buffers在Content Provider與Clients之間共享內存。
      View Code

      4.3分配與回收內存

          每一個進程的Dalvik heap都反映了使用內存的占用范圍。這就是通常邏輯意義上提到的Dalvik Heap Size,它可以隨著需要進行增長,但是增長行為會有一個系統為它設定的上限。
      邏輯上講的Heap Size和實際物理意義上使用的內存大小是不對等的,Proportional Set Size(PSS)記錄了應用程序自身占用以及和其他進程進行共享的內存。
      View Code

      4.4限制應用的內存

          為了整個Android系統的內存控制需要,Android系統為每一個應用程序都設置了一個硬性的Dalvik Heap Size最大限制閾值,這個閾值在不同的設備上會因為RAM大小不同而各有差異。如果你的應用占用內存空間已經接近這個閾值,此時再嘗試分配內存的話,很容易引起OutOfMemoryError的錯誤。
      ActivityManager.getMemoryClass()可以用來查詢當前應用的Heap Size閾值,這個方法會返回一個整數,表明你的應用的Heap Size閾值是多少Mb(megabates)。
      View Code

      4.5應用切換

      1.Android系統并不會在用戶切換應用的時候做交換內存的操作。Android會把那些不包含Foreground組件的應用進程放到LRU Cache中。例如,當用戶開始啟動了一個應用,系統會為它創建了一個進程,但是當用戶離開這個應用,此進程并不會立即被銷毀,而是會被放到系統的Cache當中,如果用戶后來再切換回到這個應用,此進程就能夠被馬上完整的恢復,從而實現應用的快速切換。
      2.如果你的應用中有一個被緩存的進程,這個進程會占用一定的內存空間,它會對系統的整體性能有影響。因此當系統開始進入Low Memory的狀態時,它會由系統根據LRU的規則與應用的優先級,內存占用情況以及其他因素的影響綜合評估之后決定是否被殺掉。
      View Code
      需要特別注意的:
      ①在Dalvik下,大部分Davik采取的都是標記-清理回收算法,而且具體使用什么算法是在編譯期決定的,無法在運行的時候動態更換。標記-清理回收算法無法對Heap中空閑內存區域做碎片整理。系統僅僅會在新的內存分配之前判斷Heap的尾端剩余空間是否足夠,如果空間不夠會觸發gc操作,從而騰出更多空閑的內存空間;這樣內存空洞就產生了。
       

      如上圖所示,第一行,在開始階段,內存分配較滿;第二行,經過GC之后,大部分對象被釋放。此時可能產生的問題是,因為沒有內存整理功能,整個頁面的4KB內存(內存分配的最小單位是頁面,通常為4KB)可能只有一個小對象,但是統計PrivateDirty/Pss時還是按照4KB計算。所以對于Dalvik虛擬機的手機來說,我們首先要盡量避免掉頻繁生成很多臨時小變量(比如說:getView, onDraw等函數中new對象),另一個又要盡量去避免產生很多長生命周期的大對象。

      ②ART在GC上不像Dalvik僅有一種回收算法,ART在不同的情況下會選擇不同的回收算法。應用程序在前臺運行時,響應性是最重要的,因此也要求執行的GC是高效的。相反,應用程序在后臺運行時,響應性不是最重要的,這時候就適合用來解決堆的內存碎片問題。因此,Mark-Sweep GC適合作為Foreground GC,而Mark-Compact GC適合作為Background GC。由于有Compact的能力存在,內存碎片在ART上可以很好的被避免,這個也是ART一個很好的能力。
      5、Android GC何時發生?

      由上文我們知道,GC操作主要是由系統決定的,但是我們可以監聽系統的GC過程,以此來分析我們應用程序當前的內存狀態。
      Dalvik虛擬機,每一次GC打印內容格式:

      D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>
      

      含義解析
      GC Reason:GC觸發原因
      GC_CONCURRENT:當已分配內存達到某一值時,觸發并發GC;
      GC_FOR_MALLOC:當嘗試在堆上分配內存不足時觸發的GC;系統必須停止應用程序并回收內存;
      GC_HPROF_DUMP_HEAP: 當需要創建HPROF文件來分析堆內存時觸發的GC;
      GC_EXPLICIT:當明確的調用GC時,例如調用System.gc()或者通過DDMS工具顯式地告訴系統進行GC操作等;
      GC_EXTERNAL_ALLOC: 僅在API級別為10或者更低時(新版本分配內存都在Dalvik堆上)
      Amount freed GC:回收的內存大小
      Heap stats:堆上的空閑內存百分比 (已用內存)/(堆上總內存)
      External memory stats: API級別為10或者更低:(已分配的內存量)/ (即將發生垃圾的極限)
      Pause time:這次GC操作導致應用程序暫停的時間。關于這個暫停的時間,在2.3之前GC操作是不能并發進行的,也就是系統正在進行GC,那么應用程序就只能阻塞住等待GC結束。而自2.3之后,GC操作改成了并發的方式進行,就是說GC的過程中不會影響到應用程序的正常運行,但是在GC操作的開始和結束的時候會短暫阻塞一段時間。
      Art虛擬機,每一次GC打印內容格式: 

      I/art:<GC_Reason><Amount_freed>,<LOS_Space_Status>,<Heap_stats>,<Pause_time>,<Total_time>
      

      基本情況和Dalvik沒有什么差別,GC的Reason更多了,還多了一個LOS_Space_Status.
      LOS_Space_Status:Large Object Space,大對象占用的空間,這部分內存并不是分配在堆上的,但仍屬于應用程序內存空間,主要用來管理 Bitmap 等占內存大的對象,避免因分配大內存導致堆頻繁 GC。 

      6.獲取內存使用情況
      通過命令行adb shell dumpsys meminfo packagename查看內存詳細占用情況:

      其中幾個關鍵的數據:
      Private(Clean和Dirty的):應用進程單獨使用的內存,代表著系統殺死你的進程后可以實際回收的內存總量**。通常需要特別關注其中更為昂貴的dirty部分,它不僅只被你的進程使用而且會持續占用內存而不能被從內存中置換出存儲。申請的全部Dalvik和本地heap內存都是Dirty的,和Zygote共享的Dalvik和本地heap內存也都是Dirty的。
      Dalvik Heap:Dalvik虛擬機使用的內存,包含dalvik-heap和dalvik-zygote,堆內存,所有的Java對象實例都放在這里。
      Heap Alloc:累加了Dalvik和Native的heap。
      PSS:這是加入與其他進程共享的分頁內存后你的應用占用的內存量,你的進程單獨使用的全部內存也會加入這個值里,多進程共享的內存按照共享比例添加到PSS值中。如一個內存分頁被兩個進程共享,每個進程的PSS值會包括此內存分頁大小的一半在內。
      Dalvik Pss內存 = 私有內存Private Dirty + (共享內存Shared Dirty / 共享進程數)
      TOTAL:上面全部條目的累加值,全局的展示了你的進程占用的內存情況。
      ViewRootImpl:應用進程里的活動窗口視圖個數,可以用來監測對話框或者其他窗口的內存泄露。
      AppContexts及Activities:應用進程里Context和Activity的對象個數,可以用來監測Activity的內存泄露。 

       

       

       

      posted on 2018-07-05 11:44  安卓筆記俠  閱讀(616)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 换着玩人妻中文字幕| 亚洲精品中文av在线| av综合亚洲一区二区| 亚洲老女人区一区二视频| 国产午夜福利精品久久不卡| 成人亚欧欧美激情在线观看| 狠狠久久五月综合色和啪| 亚洲精品天天影视综合网| 日韩毛片在线视频x| 中文字幕人妻有码久视频| 亚洲伊人成无码综合网| 亚洲综合av一区二区三区| 国产资源精品中文字幕| 科技| 午夜精品福利亚洲国产| 精品视频在线观看免费观看| 粗壮挺进人妻水蜜桃成熟| 亚洲av熟女国产一二三| 蜜桃无码一区二区三区| 亚洲狠狠婷婷综合久久久久图片| 啊轻点灬大JI巴太粗太长了在线 | 在线中文字幕亚洲日韩2020| 国内精品久久久久久无码不卡| 亚洲成人午夜排名成人午夜| 中文文字幕文字幕亚洲色| 国产suv精品一区二区| 国产精品亚洲专区无码破解版| 亚洲精品日韩在线丰满| 国产午夜一区二区在线观看 | 久章草在线毛片视频播放| 日本中文字幕不卡在线一区二区| 成人中文在线| 激情综合网激情五月激情| 99er热精品视频| 欧美高清狂热视频60一70| 亚洲国产码专区在线观看| 亚洲综合一区二区三区不卡| 亚洲一区中文字幕人妻| 国产精品一区二区久久精品 | 999福利激情视频| 亚洲美女少妇偷拍萌白酱|