安卓應用的內存每每是有限的,從開始的8M到16M,24M,32M,48M,64M等逐步變大,但內存的變大是因爲分辨率的提升致使,並不意味着能夠隨意聲明使用內存,而不及時回收(即便Java有本身的垃圾回收機制,但內存太高會引發應用變卡,體驗流暢性降低)。java
下降應用內存消耗的辦法有如下幾種常見辦法:android
一、圖片聲明使用的context使用Application,回收時清除ImageView的drawableweb
二、使用viewStub佔位,避免常用gone方法,減小對象的加載和初始化數據庫
三、使用merge把能合併的佈局通通合併,在hierachyviewer裏面能夠看到佈局的複雜度canvas
四、去掉decorView和window的背景,每每因爲應用有自身的色調搭配app
五、經過canvas的clip方法,避免在看不到的地方畫圖,經過quickReject方法來在肯定的區域好比矩形內繪製,ide
跳過非既定區域內繪製工具
六、使用9path文件和自定義圖片,以及透明背景,來防止過分繪製佈局
七、列表能夠給定一個高度(根據item的高度來動態設置),來防止重複計算高度和執行佈局方法優化
八、合理選擇組件,選擇簡單的而非複雜的組件(緣由,若是你自定義過複雜組件本身就會明白)
九、開啓新進程做爲服務進程和工具進程-最大招,有效下降當前應用的內存消耗
避免內存泄露的幾個辦法:
一、及時清除對象或回調引用的context,下降引用鏈長度
/** * 清除頁面的ImageView的引用鏈 * @param view */ public static void unbindDrawables(View view) { if (view.getBackground() != null) { view.getBackground().setCallback(null); } if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { unbindDrawables(((ViewGroup) view).getChildAt(i)); } ((ViewGroup) view).removeAllViews(); } }
二、Bitmap用前根據屏幕dpi或自定義要求進行壓縮,事後及時回收
三、Cursor對象及時關閉,避免對數據庫對象的長期引用
四、關鍵地方作空判斷,頁面關閉時及時回收對象
五、context儘可能使用application,避免頁面關閉時,因爲引用存在而不能及時回收對象
六、避免在for循環中聲明對象(一會兒無數個對象產生,內存暴增),引用能寫在外面最好,如array.length,直接用
int size獲取值,再遍歷
七、打開開發者模式中的CPU繪製選項,根據屏幕顯示的紅黃藍來辨別頁面的繪製狀況
八、handler每每引用context,使用弱引用的方式處理
public WeakHandler handler = new WeakHandler(this); public class WeakHandler extends Handler { WeakReference<Context> mContextWeakReference; public WeakHandler(Context context) { mContextWeakReference = new WeakReference<Context>(context); } @Override public void handleMessage(Message msg) { if (mContextWeakReference.get() == null || msg == null) { return; } boolean handled = !handleMessageDelegate(msg.what, msg.obj); if (handled) { if (msg.what < 0) { handleErrorMessage(msg); } else { handlePtrMessage(msg); } } } }
九、通常webView也會有內存泄露的問題出現,每每因爲引用未刪除,自身的view仍然存在,在進程一系列操做後,仍可使用開啓新進程來下降應用內存
/** * 優化內存最後一招-開啓新進程 */ @Override protected void onDestroy() { if (mWebView != null) {// remove webView, prevent chromium to crash ViewParent parent = mWebView.getParent(); if (parent != null) { ((ViewGroup) parent).removeView(mWebView); } // 退出時調用此方法,移除綁定的服務,不然某些特定系統會報錯 mWebView.getSettings().setJavaScriptEnabled(false); // 解決Receiver not registered: // android.widget.ZoomButtonsController mWebView.setVisibility(View.GONE); mWebView.removeAllViews(); mWebView.clearCache(false); mWebView.stopLoading(); mWebView.destroy(); mWebView = null; setConfigCallback(null); } super.onDestroy(); } /** * 刪除引用 * @param windowManager */ public void setConfigCallback(WindowManager windowManager) { try { Field field = WebView.class.getDeclaredField("mWebViewCore"); field = field.getType().getDeclaredField("mBrowserFrame"); field = field.getType().getDeclaredField("sConfigCallback"); field.setAccessible(true); Object configCallback = field.get(null); if (null == configCallback) { return; } field = field.getType().getDeclaredField("mWindowManager"); field.setAccessible(true); field.set(configCallback, windowManager); } catch(Exception e) { } }
檢查內存泄露的工具備:Lint(inspect code-performance)、Mat(case gc-分析hprof文件)、LeakMemory(Log日誌彈窗)、As自帶(Monitor-Dump Java Heap),更多介紹