国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

afaf

2019-11-09 18:42:15
字體:
來源:轉載
供稿:網友

轉載請注明原文地址:http://blog.csdn.net/mxm691292118/article/details/51020023

我把Android重難點和讀書筆記都整理在github上:https://github.com/miomin/AndroidDifficulty

如果你覺得對你有幫助的話,希望可以star/follow一下喲,我會持續保持更新。


一、內存泄露

垃圾回收器無法回收原本應該被回收的對象,這個對象就引發了內存泄露。內存泄露的危害: (1)過多的內存泄露最終會導致內存溢出(OOM)(2)內存泄露導致可用內存不足,會觸發頻繁GC,不管是Android2.2以前的單線程GC還是現在的CMS和G1,都有一部分的操作會導致用戶線程停止(就是所謂的Stop the world),從而導致UI卡頓。

二、內存溢出(OOM)

Android為每個進程設置Dalvik Heap Size閾值,這個閾值在不同的設備上會因為RAM大小不同而各有差異。如果APP想要分配的內存超過這個閾值,就會發生OOM。

ActivityManager.getMemoryClass()可以查詢當前APP的Heap Size閾值,單位是MB。

在3.x以前,Bitmap分配在Native heap中,而在4.x之后,Bitmap分配在Dalvik或ART的javaheap中。

Android 2.x系統,當dalvik allocated + native allocated + 新分配的大小 >= dalvik heap 最大值時候就會發生OOM,也就是說在2.x系統中,考慮native heap對每個進程的內存限制。

Android 4.x系統,廢除了native的計數器,類似bitmap的分配改到dalvik的java heap中申請,只要allocated + 新分配的內存 >= dalvik heap 最大值的時候就會發生OOM(art運行環境的統計規則還是和dalvik保持一致),也就是說在4.x系統中,不考慮native heap對每個進程的內存限制,native heap只會收到本機總內存(包括RAM以及SWAP區或分頁文件)的限制。

三、如何避免內存泄漏

參考在MDCC 2015中國移動開發者大會上胡凱前輩的講述,整理總結。

1、使用輕量的數據結構

使用ArrayMap/SparseArray來代替HashMap,ArrayMap/SparseArray是專門為移動設備設計的高效的數據結構。

HashMap實現原理

HashMap內部使用一個默認容量為16的數組來存儲數據,采用拉鏈法解決hash沖突(數組+鏈表),如下圖: 這里寫圖片描述

Entry存儲的內容有key、value、hash值、next指針,通過計算hash(key)%len找到Entry在數組中的位置。

缺點:(1)就算沒有數據,也需要分配默認16個元素的數組(2)一旦數據量達到Hashmap限定容量的75%,就將按兩倍擴容

SparseArray

支持int類型,避免自動裝箱,但是也只支持int類型的key內部通過兩個數組來進行數據存儲的,一個存儲key,另外一個存儲value因為key是int,在查找時,采用二分查找,效率高,SparseArray存儲的元素都是按元素的key值從小到大排列好的。 (Hashmap通過遍歷Entry數組來獲取對象)默認初始size為0,每次增加元素,size++SparseArray中put方法的源碼如下:

ArrayMap

跟SparseArray一樣,內部兩個數組,但是第一個存key的hash值,一個存value,對象按照key的hash值排序,二分查找也是按照hash查找index時,傳入key,計算出hash,通過二分查找hash數組,確定index

2、不要使用Enum

這點在Google的Android官方培訓課程提到過,具體可以參考胡凱前輩的《 Android性能優化典范(三)》。

3、大胖子Bitmap的處理

Bitmap壓縮Lru機制處理Bitmap(下一節博客會詳細講解),也可以使用那些有名的圖片緩存框架。

4、不要使用String進行字符串拼接

嚴格的講,String拼接只能歸結到內存抖動中,因為產生的String副本能夠被GC,不會造成內存泄露。

頻繁的字符串拼接,使用StringBuffer或者StringBuilder代替String,可以在一定程度上避免OOM和內存抖動。

5、非靜態內部類內存泄露

在Activity中創建非靜態內部類,非靜態內部類會持有Activity的隱式引用,若內部類生命周期長于Activity,會導致Activity實例無法被回收。(屏幕旋轉后會重新創建Activity實例,如果內部類持有引用,將會導致旋轉前的實例無法被回收)。

解決方案:如果一定要使用內部類,就改用static內部類,在內部類中通過WeakReference的方式引用外界資源。

正確的代碼示例:

static class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> { PRivate String url; private WeakReference<PhotoAdapter> photoAdapter; public ImageDownloadTask(PhotoAdapter photoAdapter) { this.photoAdapter = new WeakReference<PhotoAdapter>(photoAdapter); } @Override protected Bitmap doInBackground(String... params) { //在后臺開始下載圖片 url = params[0]; Bitmap bitmap = photoAdapter.get().loadBitmap(url); if (bitmap != null) { //把下載好的圖片放入LruCache中 String key = md5Tools.decodeString(url); photoAdapter.get().put(key, bitmap); } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); //把下載好的圖片顯示出來 ImageView mImageView = (ImageView) photoAdapter.get().mGridView.get().findViewWithTag(MD5Tools.decodeString(url)); if (mImageView != null && bitmap != null) { mImageView.setImageBitmap(bitmap); photoAdapter.get().mDownloadTaskList.remove(this);//把下載好的任務移除 } } }123456789101112131415161718192021222324252627282930313233123456789101112131415161718192021222324252627282930313233

6、匿名內部類內存泄漏

跟非靜態內部類一樣,匿名內部類也會持有外部類的隱式引用,比較常見的情況有,耗時Handler,耗時Thread,都會造成內存泄漏,解決方式也是static+WeakReference,下面給出正確寫法。

Handler的正確寫法:

private static class MyHandler extends Handler { private final WeakReference<Context> context; private MyHandler(Context context) { this.context = new WeakReference<Context>(context); } @Override public void handleMessage(Message msg) { switch (msg.what) { } }}private final MyHandler mHandler = new MyHandler(this);private static final Runnable sRunnable = new Runnable() { @Override public void run() { }};@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); // 發送一個10分鐘后執行的一個消息 mHandler.postDelayed(sRunnable, 600000);}12345678910111213141516171819202122232425262728293031321234567891011121314151617181920212223242526272829303132Thread的正確寫法:private static class MyThread extends Thread { @Override public void run() { while (true) { // TODO 耗時任務 } }}new MyThread().start();12345678910111234567891011

7、Context持有導致內存泄漏

Activity Context被傳遞到其他實例中,這可能導致自身被引用而發生泄漏。解決:對于大部分非必須使用Activity Context的情況(創建Dialog的Context必須是Activity Context),應該使用application Context。

8、記得注銷監聽器

注冊監聽器的時候會add Listener,不要忘記在不需要的時候remove掉Listener。

9、資源文件需要選擇合適的文件夾進行存放

hdpi/xhdpi/xxhdpi等等不同dpi的文件夾下的圖片在不同的設備上會經過scale的處理。例如我們只在hdpi的目錄下放置了一張100100的圖片,那么根據換算關系,xxhdpi的手機去引用那張圖片就會被拉伸到200200。需要注意到在這種情況下,內存占用是會顯著提高的。對于不希望被拉伸的圖片,需要放到assets或者nodpi的目錄下。

10、謹慎使用static對象

static對象的生命周期過長,應該謹慎使用

11、謹慎使用單例中不合理的持有

單例中的對象生命周期與應用一致,注意不要在單例中進行不必要的外界引用持有。如果一定要引用外部變量,需要在外部變量生命周期結束的時候接觸引用(賦為null)。

12、一定要記得關閉無用連接

在onDestory中關閉Cursor,I/O,數據庫,網絡的連接用完記得關閉。

注意:謹慎使用lager heap

不同的設備有不容的RAM,他們為應用程序設置了不同大小的Heap的閾值。雖然可以通過largeHeap=true的屬性來為應用獲得一個更大的heap空間,然后通過getLargeMemoryClass()來獲取到這個更大的heap閾值。但是你要注意,largeHeap只是為了一些本來就需要大量內存的APP存在,比如圖墻和圖片編輯軟件。所以,不要隨意的使用large heap,否則會影響系統整體的用戶體驗,會使每次gc時間更長。

四、內存泄露檢測

這里介紹LeakCanary,一款非常好用的內存泄露檢測工具,安裝在手機上,能夠通過Log的方式告訴你是哪塊代碼發生了內存泄露。

使用方法,在Application中install LeakCanary(默認只能檢測Activity內容的內存泄露):

public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); }}12345671234567想要檢測更多,首先注冊一個RefWatcher:public class MyApplication extends Application { private static RefWatcher sRefWatcher; @Override public void onCreate() { super.onCreate(); sRefWatcher = LeakCanary.install(this); } public static RefWatcher getRefWatcher() { return sRefWatcher; }}12345678910111213141234567891011121314然后對某個可能發生泄露的占用大內存的對象進行監測:MyApplication.getRefWatcher().watch(sLeaky);11對Fragment、BroadcastReceiver、Service進行監測:public class MyFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); MyApplication.getRefWatcher().watch(this); }}12345671234567具體就不多說,大家去LeakCanary的Github上看就行了,地址是:https://github.com/square/leakcanary

參考文獻

Andorid內存優化之OOMAndroid性能優化典范(一)Android性能優化典范(二)Android性能優化典范(三)Android性能優化之內存篇Android官方學習教程
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 呼玛县| 通化县| 醴陵市| 迁西县| 昭苏县| 化州市| 竹溪县| 博客| 乌兰察布市| 开化县| 广安市| 塘沽区| 无棣县| 威海市| 萍乡市| 高淳县| 沙河市| 米林县| 枣庄市| 三江| 博兴县| 合江县| 长子县| 湖南省| 南皮县| 桃园县| 平和县| 交城县| 灌南县| 南漳县| 贵德县| 富民县| 清河县| 徐闻县| 商丘市| 孟连| 太仆寺旗| 高州市| 遂昌县| 偏关县| 娱乐|