精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Android內存管理

前一段時間自己學習了下Android內存管理相關的東西,在部門內部做了一次技術分享。作為一個在公開場合會靦腆,上不了臺面,表達能力也不行的人來說是一個不小的進步。一直很佩服墻內墻外的牛人們堅持寫博客和大家分享的精神。嗯,今天就將上次的技術分享寫在博客里面,希望對大家有幫助。

下面分為4個部分來闡述: 

  • Android內存管理機制 
  • Android App中內存管理優化 
  • 檢測內存使用情況 
  • 內存泄漏 

一、Android系統內存管理機制

1.Linux vs. Windows
兩者都能將物理內存中長時間不使用的內容轉移到磁盤空間上,再次訪問時才加載回內存。
Windows只在應用程序需要的時候才會分配內存,不能充分充分利用內存。
Linux充分利用物理內存空間(RAM)及其高速讀寫特性,將程序調用過程中的硬盤數據讀入內存,提高數據訪問性能。 

Android是基于Linux系統的,繼承了Linux的很多優秀特性。但是Android沒有可交換磁盤空間(swap space),所有的內存都存在于RAM中,這使得Android系統釋放內存的唯一方式就是釋放引用的對象。

2.Android進程和內存

Android進程包含2種:
(1)Native進程:采用C/C++實現,不包含dalvik實例的進程。/system/bin/目錄下面的文件運行后都是以native進程存在的。
(2)Java進程:Android中運行于dalvik虛擬機上的進程。dalvik虛擬機的宿主進程由fork()系統調用創建,所以每一個Java進程都存在于一個Native進程中。由于每個Java存在一個虛擬機實例,因此Java進程內存分配要比Native進程復雜。 

3.Android中的java程序為啥容易OOM?
Android對dalvik的vm heapsize作了限制,當Java進程申請的內存超過閾值時,會拋出OOM異常。
程序發生OOM并不能說明RAM不足,只能說明是Java heap超出了dalvik vm heapsize的閾值。
當RAM內存不足時,memory killer會殺掉低優先級進程,保證高優先級進程有更多內存。 

Google之所以這樣設計,處于以下考慮:
為了讓比較多的進程同時常駐內存,這樣程序啟動時不需要每次都加載到內存,能夠給用戶更快的響應。通過限制每個應用程序的內存,使得Android系統內存中同時常駐多個進程。

4.如何繞過dalvik vm heapsize的限制
(1)創建子進程
(2)使用JNI在native heap上申請內存(推薦)
(3)使用RAM中的顯存空間

二、Android App中內存管理優化

1.Use services sparingly 

  • 盡量少用Service,當后臺任務運行完成時及時關閉Service
  • IntentService取代Service,當后臺任務完成時自動結束服務自身

原因:Service啟動時,Service所在進程會保持運行狀態,Service所占用的內存不會釋放,使得進程占用資源過多,因此系統LRU cache中能同時保持的進程數減少,應用程序的切換變得更低效。由于沒有足夠的進程來處理系統中的Service,也會導致系統穩定性變差。

2.當UI不可見或內存緊張時,釋放內存:
Activity的回調方法onTrimMemory(int level)中根據level的不同釋放內存。
進程不在緩存中:

  • TRIM_MEMORY_RUNNING_MODERATE 應用程序正在運行,并且處于非killable狀態,此時設備內存低(low),系統主動殺LRU緩存中的進程
  • TRIM_MEMORY_RUNNING_LOW 應用程序正在運行,并且處于非killable狀態,此時設備內存很低(much lower),需要釋放沒用的資源
  • TRIM_MEMORY_RUNNING_CRITICAL 應用程序正在運行,但是系統已殺死LRU緩存中的大部分進程,此時需要釋放所有不至關重要的資源。如果系統不能回收足夠的內存,就會清掉LRU中所有的進程以及服務進程。 

進程在LRU緩存中:

  • TRIM_MEMORY_BACKGROUND 系統低內存下運行,程序進程位于LRU緩存列表的開頭位置。雖然程序進程被kill的概率不大,但是系統可能正在殺LRU中的進程。你需要釋放容易恢復的資源以便程序進程還在LRU list中,當從其他App返回時,能快速恢復現場。
  • TRIM_MEMORY_MODERATE 系統低內存下運行,程序進程位于LRU緩存列表的中間位置。你的進程被殺掉的可能性變大。
  • TRIM_MEMORY_COMPLETE 系統低內存下運行,程序進程最先容易被系統殺死。你需要釋放所有對于恢復程序狀態不至關重要的資源。 

API14開始有onTrimMemory()回調;API 14以下使用的是onLowMemory(),等價于TRIM_MEMORY_COMPLETE

3.恰當使用Bitmap
加載bitmap時,盡量保證bitmap分辨率和屏幕分辨率匹配,對于大分辨率的bitmap需要進行壓縮處理。 


(1) Android 2.3.x(API 10)及以下的系統
bitmap像素數據實際存儲于native內存中,在java heap中只是保留對象的引用,因此在java heap中內部都顯示同一個大小。內存回收需主動調用recycle(),GC失效
(2) 在Android 3.0(API 11)及以上的系統
bitmap像素數據存儲于java heap中,無需主動調用recycle(),由GC管理內存。
(3) 通過內存分析工具調試bitmap內存時,在Android 3.0的系統上進行,因為大部分內存分析工具只能分析java內存

4.使用SparseArraySparseBooleanArrayLongSparseArray等優化的數據容器代替HashMap 

5.使用static const代替enum

6.非必要情況下,少用抽象

7.對于序列化數據,使用nano protobuf

8.盡量少使用依賴注入框架

9.謹慎使用第三方庫

10.使用ProGuard去除不必要的代碼

11.apk打包簽名時,使用zipalign工具對齊

12.使用多進程
一般情況下,大多數應用程序都不需要使用多進程。只有對于需要在后臺和前臺同時運行,并且前后臺單獨管理的程序才涉及到多進程(如音樂播放器)。
使用多進程方法:

<service android:name=".PlaybackService"     android:process=":background" />

一個空進程占用大概1.4MB內存,如果在該進程中操作UI,內存占用將是原來的好幾倍。因此如果使用多進程,一般一個進程用于UI,其他進程不要有任何UI相關操作。

三、檢測內存使用情況

1.分析Logcat信息

D/dalvikvm:<GC_Reason><Amount_freed>,<Heap_stats>,<External_memory_stats>,<Pause_time> 參數解釋:
  • GC_Reason 發生GC的原因(GC_CONCURRENT,GC_FOR_MALLOC,GC_HPROF_DUMP_HEAP,GC_EXPLICIT,GC_EXTERNAL_ALLOC)
  • Amount_freed 垃圾回收釋放的內存
  • Heap_stats java堆內存可用百分比(number of live objects)/(total heap size)
  • External_memory_stats (amount of allocated memory)/(limit at which collection will occur)
  • Pausing_time 取決于heap大小,對于并發操作可能會有2個pausing time

2.利用Eclipse的DDMS視圖自帶的內存分析工具

  • 觀察heap內存變化情況
    DDMS -> Update heap -> Cause GC
  • 跟蹤內存分配情況
    DDMS -> Allocation Tracker -> Start Tracking -> GetAllocations
    跟蹤內存分配的方法,可用定位到具體某個實例,某個線程,某個類,某個文件和某一行。

3.使用adb命令行 

adb shell dumpsys meminfo <package_name>

4.使用MAT內存分析工具
下載eclipse插件memory analyze tool
操作DDMS -> Dump HPROF file -> save,分析Histigram view和Dominator tree內容。

重要概念:shallow heap和retained heap

  • shallow heap 對象本身占用內存大小
  • retained heap 通過釋放這個對象總共可以回收的內存

四、內存泄漏

1.GC原理


GC會選擇一些還存活的對象作為內存遍歷的根節點GC Roots(如thread stack中的變量,JNI中的全局變量,zygote中的class loader對象等),對heap進行遍歷,沒有被直接或間接遍歷到的引用會被GC回收,能被遍歷到的不能被回收。
內存泄露:某些不再使用的對象被GC Roots引用,導致不能回收,使實際可使用內存變小。

2.引起內存泄露的因素
(1)長時間保持對Activity,Context,View,Drawable和其他對象的引用
(2)非靜態內部類
(3)持有對象的時間超出需要的時間

3.常見的內存泄露
(1)非靜態內部類的靜態實例
(2)Activity使用靜態成員
(3)Handler、HandlerThread使用時的問題
(4)register某個對象后缺少對應的unregister操作
(5)集合對象未清理,資源對象未關閉
(6)Dialog或PopupWindow未關閉引起的window leak
(7)不良代碼造成的壓力。如Bitmap使用不當;構造adapter時,沒有使用緩存的convertView;在循環方法中創建對象。

4.改進建議 

  • 與View無關的操作盡量使用Application Context
  • 使用靜態內部類
  • 靈活使用弱引用WeakReference
  • 對對象的持有時間不要超過其生命周期

本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android學習之 內存管理機制與應用內存優化
Android Training - 管理應用的內存
Android最佳性能實踐(一)
Android內存泄漏分析及調試
Android性能優化典范
ANDROID 探究oom內幕
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 合水县| 临湘市| 峨眉山市| 晋州市| 镇坪县| 宝应县| 渑池县| 习水县| 和田市| 黄骅市| 萝北县| 镇安县| 华蓥市| 中江县| 增城市| 渝中区| 墨竹工卡县| 古丈县| 双峰县| 高要市| 永城市| 浮梁县| 乐清市| 文安县| 阿图什市| 广河县| 丘北县| 凭祥市| 临澧县| 穆棱市| 舒兰市| 白沙| 谢通门县| 山东省| 呼和浩特市| 田阳县| 平潭县| 滦平县| 博兴县| 右玉县| 凤山县|