Andoird優化,內存優化
內存管理
但這也僅僅是為大家提供一些思路與較為全面的總結,算不上什麼,希望有錯誤或問題在下面評論。
最後完結以後會將思維導圖與優化框架整理出來,請期待。
如果程序會運行著崩潰、或者突然被系統殺死,那你就該繼續往下看。
這是這章的思維導圖,不過壓縮嚴重,下面是樣圖,原圖和源文件在最下方鏈接。還是值得下載的。
題記
應用的生存期絕大部分時間都用於處理內存中的數據,雖然我們大多數人都意識到在手機上要儘可能少使用內存,但並非所有人都認識到了內存使用對性能的影響。所以,下面我們來討論一下。
一、談談移動設備中的內存
無論分配給應用多少內存,它都不會滿足。
移動設備和傳統的電腦有兩個很大的差異;
物理內存大小
虛擬內存交換能力
要在一定設備上使用儘可能少的內存,既是經驗也是常識。
好處:
減少碰到oom異常的風險
提升性能
性能取決於以下三個因素( 我們會在下面講解)
CPU如何操縱特定的數據類型
數據和指令需要佔用多少存儲空間
二、採用合適的數據類型
使用long比short和int慢
同樣,只使用double及混用float和double,比只用float慢。
注意:由於並不是所有指令的執行時間都相同,再加上cpu很複雜,所以並不能推測出具體的時間。 short數組排序遠比其他類型數組快
原因: short使用計數排序,演算法複雜度是線性的 而int和long使用快速排序演算法
處理64位類型(long或double)比處理32位類型慢
總的來說,
就是:
1、處理大量數據時,使用可以滿足要求的最小數據類型
2、避免類型轉換。盡量保持類型一致,儘可能在計算中使用單一類型。
3、如果有必要取得更好的性能,推倒重來,但要認真處理。
三、你需要知道的訪問內存
1、操縱較大類型的數據代價較高,因為用到了指令較多。 直觀的來說,指令越多性能越差,CPU需要做很多額外的工作
2、此外、代碼和數據都駐留在內存中,訪問內存本身也有開銷。 因為訪問內存會產生一些開銷,CPU會把最近訪問的內容緩存起來,無論是內存讀還是寫。
3、CPU通常使用兩級緩存或者三級緩存:
一級緩存
二級緩存
三級緩存(一般用於伺服器機或遊戲機器)
4、當數據或指令在緩存中找不到時,就是緩存未命中。這是需要從內存中讀取數據或指令。
緩存未命中幾種情況:
指令緩存讀未命中
數據緩存讀未命中
寫未命中
注意:第一種緩存未命中最關鍵,因為CPU要一直等到從內存中讀出指令,才可以繼續執行。
另外:現代CPU都能夠自動預取內存,為了避免或者只說是限制了緩存未命中情況的發生。
四、通過垃圾收集管理內存
1、Java的一個非常重要的優點是垃圾收集
原理: 不再使用的對象內存會被垃圾收集器釋放(回收)。
注意:還是會出現內存泄露的情況。
垃圾收集器會幫你管理內存,它做的不僅僅是釋放不用的內存。
2、內存泄漏:
只有當某個對象不再被引用時,它的內存才會被回收,當該被釋放的對象引用仍然存在時就會發生內存泄漏。
一個典型例子就是,由於屏幕旋轉,整個Activity對象會有泄露 很嚴重!因為Activity對象佔用相當多內存。
3、 避免內存泄漏方案。(大多數只能用來分析,並不會告訴你是否內存泄漏)
DDMS視圖裡面的Heap與Tracker 可以跟蹤內存使用和分配情況。 AS裡面的monitor 有內存、網路、等四個視圖
StrictMode類 會將檢測到的違規操作,將結果寫到日誌中。 只能用來分析,並不會告訴你是否內存泄漏
OneAPM 用過,並且也去面試過,很不錯。
五、通過Java中的引用來更好的管理
1、內存釋放是垃圾收集器的一個重要的特性,在垃圾收集器中它的作用比在內存管理系統中大得多。
2、Java定義了4中類型的引用
強(Strong):
其實就是普通的創建對象,保持無用對象的強引用可能會導致內存泄漏
軟(Soft):
其實軟引用和弱引用在本質上是類似的,軟引用適用於緩存,它可以自動刪除緩存中的條目
弱(Weak)
保障下次垃圾回收時基本會收走
虛(Phantom)
幾乎很少用到
3、當需要緩存或映射時,你不必實現類似的內存管理系統。精心規劃引用後,大部分工作可以放心地交給垃圾收集器完成。
4、 垃圾收集
垃圾收集可能會再不定的時間觸發,你幾乎無法控制它的時機。
但是有時,你可以通過System.gc( );提醒一下Android,
雖然如此,垃圾收集機制發生時間最終時間是不由你確定的。
5、 垃圾收集發生在應用的主線程,所以:
很可能降低響應速度和性能。
在及時遊戲中會出現丟幀,因為有太多時間花在垃圾收集上。
Andorid2.3有了轉機,垃圾收集工作轉移到了一個單獨的線程。比以前的Android版本好太多了
六、通過系統的API可以了解、管理內存
1、 Android定義了幾個API,你可以用他們來了解系統中還剩多少可用內存和用了多少內存
ActivityManager的:
getMomoryInfo() getMomoryClass() getLargeMeoryClass()
Debug的
dumpHprofData() getNativeHeapAllocatedSize() getNativeHeapSize()
提示:
在應用的manifest文件中把android:largeHeap設為true,就可以讓應用使用更大的堆。
七、當內存少的時候可以這樣處理
ComponentCallbacks介面定義了API onLowMomory( ),它對所有應用組> 件都是相同的。當它被調用時,組件基本會被要求釋放那些並不會用到的內存。
可以被釋放的內容:
緩存或緩存條目(如使用強引用的LruCache)
可以再次按需生成的點陣圖對象
不可見的布局對象
資料庫對象
八、通過5R法來對ANDROID內存進行優化:
1.Reckon(計算)
首先需要知道你的app所消耗內存的情況,知己知彼才能百戰不殆
通過上文提到的工具進行查看消耗,這裡再給大家推薦一個工具
Memory Analysis Tool(MAT):
可以轉換成餅圖和表格,直觀、好用。
2.Reduce(減少)
Reduce的意思就是減少,直接減少內存的使用是最有效的優化方式。
例如:
Bitmap:
Bitmap是內存消耗大戶,絕大多數的OOM崩潰都是在操作Bitmap時產生的,下面來看看幾個處理圖片的方法:
圖片顯示:
例如在列表中僅用於預覽時載入縮略圖(thumbnails )。
只有當用戶點擊具體條目想看詳細信息的時候,這時另啟動一個fragment/activity/對話框等等,去顯示整個圖片
圖片大小:
使用BitmapFactory.Options設置inSampleSize, 這樣做可以減少對系統資源的要求。
BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options(); bitmapFactoryOptions.inJustDecodeBounds = true; bitmapFactoryOptions.inSampleSize = 2; // 這裡一定要將其設置回false,因為之前我們將其設置成了true // 設置inJustDecodeBounds為true後,decodeFile並不分配空間,即,BitmapFactory解碼出來的Bitmap為Null,但可計算出原始圖片的長度和寬度 options.inJustDecodeBounds = false; Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);
圖片像素:
Android中圖片有四種屬性,分別是:
ALPHA_8:每個像素佔用1byte內存
ARGB_4444:每個像素佔用2byte內存
ARGB_8888:每個像素佔用4byte內存 (默認)
RGB_565:每個像素佔用2byte內存
Android默認的顏色模式為ARGB_8888,這個顏色模式色彩最細膩,顯示質量最高。但同樣的,佔用的內存也最大。 所以在對圖片效果不是特別高的情況下使用RGB_565(565沒有透明度屬性),如下:
public static BitmapreadBitMap(Contextcontext, intresId) { BitmapFactory.Optionsopt = newBitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.RGB_565; opt.inPurgeable = true; opt.inInputShareable = true; //獲取資源圖片 InputStream is = context.getResources().openRawResource(resId); return BitmapFactory.decodeStream(is, null, opt); }
圖片回收:
使用Bitmap過後,就需要及時的調用Bitmap.recycle()方法來釋放Bitmap佔用的內存空間,而不要等Android系統來進行釋放。
bitmap.recycle(); bitmap = null;
捕獲異常:
Bitmap bitmap = null; try { // 實例化Bitmap bitmap = BitmapFactory.decodeFile(path); } catch (OutOfMemoryError e) { // 捕獲OutOfMemoryError,避免直接崩潰 } if (bitmap == null) { // 如果實例化失敗 返回默認的Bitmap對象 return defaultBitmapMap; }
修改引用:
如果只是想避免OutOfMemory異常的發生,則可以使用軟引用。如果對於應用的性能更在意,想儘快回收一些佔用內存比較大的對象,則可以使用弱引用。
另外,和弱引用功能類似的是WeakHashMap。WeakHashMap對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的回收,回收以後,其條目從映射中有效地移除。WeakHashMap使用ReferenceQueue實現的這種機制。
3.Reuse(重用)
核心思路就是將已經存在的內存資源重新使用而避免去創建新的,最典型的使用就是緩存(Cache)和池(Pool)。
4.Recycle(回收)
Thread(線程)回收:
Cursor(游標)回收:
@Override protected void onDestroy() { if (mAdapter != null && mAdapter.getCurosr() != null) { mAdapter.getCursor().close(); } super.onDestroy(); }
還有接收器、流等等。
5.Review(檢查)
Code Review(代碼檢查):
Code Review主要檢查代碼中存在的一些不合理或可以改進優化的地方,
UI Review(視圖檢查):
Android對於視圖中控制項的布局渲染等會消耗很多的資源和內存,所以這部分也是我們需要注意的。
減少視圖層級:
減少視圖層級可以有效的減少內存消耗,因為視圖是一個樹形結構,每次刷新和渲染都會遍歷一次。
hierarchyviewer:
想要減少視圖層級首先就需要知道視圖層級,所以下面介紹一個SDK中自帶的一個非常好用的工具hierarchyviewer。
你可以在下面的地址找到它:your sdk pathsdk ools
總結
刪除對象應該仔細考慮,因為重新創建是需要開銷的。
如果沒有釋放出足夠的內存可能會導致Android系統更激進的行為(如殺死進程)。
如果應用進程被殺掉了,用戶下次使用又要從頭開始。因此,應用不僅要表現出色,也要釋放儘可能多的資源。 代碼中推遲初始化是一個好的方式。
內存在嵌入式設備上是稀缺資源。儘管今天的手機和平板電腦的內存越來越多, 但這些設備也在運行越來越複雜的系統和應用。有效的使用內存, 不僅可以使應用在舊設備上運行時佔用較少的內存, 還可以讓程序跑的更快。請記住,應用對內存的需求是無止境的。
Anroid優化(二)_內存優化.xmind 下載:http://pan.baidu.com/s/1hsK2Co0 密碼:abcs
來自:http://www.jianshu.com/p/afd4d8a6dcd6


※Android圖片載入框架最全解析二,從源碼的角度理解Glide的執行流程
TAG:殘殤 |