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(線程)回收:
Thread t = new Thread() {
public void run() {
while (true) {
try {
Thread.sleep(1000);
System.out.println("thread is running...");
} catch (InterruptedException e) {
}
}
}
};
t.start();
t = null;
System.gc();
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 path\sdk\tools
總結
刪除對象應該仔細考慮,因為重新創建是需要開銷的。
如果沒有釋放出足夠的內存可能會導致Android系統更激進的行為(如殺死進程)。
如果應用進程被殺掉了,用戶下次使用又要從頭開始。因此,應用不僅要表現出色,也要釋放盡可能多的資源。 代碼中推遲初始化是一個好的方式。
內存在嵌入式設備上是稀缺資源。盡管今天的手機和平板電腦的內存越來越多, 但這些設備也在運行越來越復雜的系統和應用。有效的使用內存, 不僅可以使應用在舊設備上運行時占用較少的內存, 還可以讓程序跑的更快。請記住,應用對內存的需求是無止境的。
Anroid優化(二)_內存優化.xmind 下載:http://pan.baidu.com/s/1hsK2Co0 密碼:abcs
來自:http://www.jianshu.com/p/afd4d8a6dcd6