Android性能優化-記憶體泄漏的8個Case

来源:https://www.cnblogs.com/ganchuanpu/archive/2018/05/25/9090636.html
-Advertisement-
Play Games

1為什麼要做性能優化? 手機性能越來越好,不用糾結這些細微的性能? Android每一個應用都是運行的獨立的Dalivk虛擬機,根據不同的手機分配的可用記憶體可能只有(32M、64M等),所謂的4GB、6GB運行記憶體其實對於我們的應用不是可以任意索取 詳情:http://10.158.0.33/bbs ...


1為什麼要做性能優化? 手機性能越來越好,不用糾結這些細微的性能? Android每一個應用都是運行的獨立的Dalivk虛擬機,根據不同的手機分配的可用記憶體可能只有(32M、64M等),所謂的4GB、6GB運行記憶體其實對於我們的應用不是可以任意索取 詳情:http://10.158.0.33/bbs/forum.php?mod=viewthread&tid=122&extra= 優秀的演算法與效率低下的演算法之間的運行效率要遠遠超過電腦硬體的的發展,雖然手機單核、雙核到4核、8核的發展,但性能優化任然不可忽略 手機應用一般使用的周期比較短,用完就關了。不像伺服器應用要長年累月運行,似乎影響不大? 現在一般的用戶都不會重啟手機,可能一個月都不會重啟。像微信這樣的APP,每天都在使用。 如果一旦發生記憶體泄漏,那麼可能一點一點的累積,程式就會出現OOM。 等應用出現卡頓、發燙等,再來關註性能優化? 所以為了我們的應用的健壯性、有良好的用戶體驗。性能優化技術,需要我們用心去研究和應用。 似乎是沒錯的。現在一般我們也都是等出現問題了再來找原因。但是學好性能優化的目的不僅僅如此,我們在編碼階段就應該從源頭來杜絕一些坑,這樣的成本比後期再來尋找原因要少得多。 2

什麼是記憶體泄漏?

JVM記憶體管理 Java採用GC進行記憶體管理。深入的JVM記憶體管理知識,推薦《深入理解Java虛擬機》。 關於記憶體泄漏我們要知道,JVM記憶體分配的幾種策略。 1. 靜態的 靜態的存儲區,記憶體在程式編譯的時候就已經分配好了,這塊記憶體在程式整個運行期間都一直存在,它主要存放靜態數據、全局的static數據和一些常量。 2.棧式的 在執行方法時,方法一些內部變數的存儲都可以放在棧上面創建,方法執行結束的時候這些存儲單元就會自動被註釋掉。棧 記憶體包括分配的運算速度很快,因為內在在處理器裡面。當然容量有限,並且棧式一塊連續的記憶體區域,大小是由操作系統決定的,他先進後 出,進出完成不會產生碎片,運行效率高且穩定 3.堆式的 也叫動態記憶體 。我們通常使用new 來申請分配一個記憶體。這裡也是我們討論記憶體泄漏優化的關鍵存儲區。GC會根據記憶體的使用情況,對堆記憶體里的垃圾記憶體進行回收。 堆記憶體是一塊不連續的記憶體區域,如果頻繁地new/remove會造成大量的記憶體碎片,GC頻繁的回收,導致記憶體抖動,這也會消耗我們應用的性能 我們知道可以調用 System.gc();進行記憶體回收,但是GC不一定會執行。 面對GC的機制,我們是否無能為力?其實我們可以通過聲明一些引用標記來讓GC更好對記憶體進行回收。

[td]

類型 回收時機 生命周期
StrongReference (強引用) 任何時候GC是不能回收他的,哪怕記憶體不足時,系統會直接拋出異常OutOfMemoryError,也不會去回收 進程終止
SoftReference (軟引用) 當記憶體足夠時不會回收這種引用類型的對象,只有當記憶體不夠用時才會回收 記憶體不足,進行GC的時候
WeakReference (弱引用) GC一運行就會把給回收了 GC後終止
PhantomReference (虛引用) 如果一個對象與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收 任何時候都有可能
開發時,為了防止記憶體溢出,處理一些比較占用記憶體並且生命周期長的對象時,可以儘量使用軟引用和弱引用。
Tip:成員變數全部存儲在堆中(包括基本數據類型,引用及引用的對象實體),因為他們屬於類,類對象最終還是要被new出來的。
局部變數的基本數據類型和引用存在棧中,應用的對象實體存儲在堆中。因為它們屬於方法當中的變數,生命周期會隨著方法一起結束
記憶體泄漏的定義 當一個對象已經不需要使用了,本該被回收時,而有另外一個正在使用的對象持有它的引用,從而導致了對象不能被GC回收。 這種導致了本該被回收的對象不能被回收而停留在堆記憶體中,就產生了記憶體泄漏。 記憶體泄漏與記憶體溢出的區別
  • 記憶體泄漏(Memory Leak)
進程中某些對象已經沒有使用的價值了,但是他們卻還可以直接或間接地被引用到GC Root導致無法回收。當記憶體泄漏過多的時候,再加上應用本身占用的記憶體,日積月累最終就會導致記憶體溢出OOM
  • 記憶體溢出(OOM)
當 應用的heap資源超過了Dalvik虛擬機分配的記憶體就會記憶體溢出 記憶體泄漏帶來的影響
  • 應用卡頓
泄漏的記憶體影響了GC的記憶體分配,過多的記憶體泄漏會影響應用的執行效率
  • 應用異常(OOM)
過多的記憶體泄漏,最終會導致 Dalvik可分配的記憶體越來越少,更加容易出現OOM 3

Android開發常見的記憶體泄漏

(1)單例造成的記憶體泄漏 錯誤示例 當調用getInstance時,如果傳入的context是Activity的context。 只要這個單例沒有被釋放,那麼這個Activity也不會被釋放一直到進程退出才會釋放。 解決方案 能使用Application的Context就不要使用Activity的Content,Application的生命周期伴隨著整個進程的周期 (2)非靜態內部類創建靜態實例造成的記憶體泄漏 錯誤示例 解決方案 將非靜態內部類修改為靜態內部類。(靜態內部類不會隱式持有外部類) (3)Handler造成的記憶體泄漏 錯誤示例 mHandler是Handler的非靜態匿名內部類的實例,所以它持有外部類Activity的引用,我們知道消息隊列是在一個Looper線程中不斷輪詢處理消息,那麼當這個Activity退出時消息隊列中還有未處理的消息或者正在處理消息,而消息隊列中的Message持有mHandler實例的引用,mHandler又持有Activity的引用,所以導致該Activity的記憶體資源無法及時回收,引發記憶體泄漏。 解決方案 創建一個靜態Handler內部類,然後對Handler持有的對象使用弱引用,這樣在回收時也可以回收Handler持有的對象,這樣雖然避免了Activity泄漏,不過Looper線程的消息隊列中還是可能會有待處理的消息,所以我們在Activity的Destroy時或者Stop時應該移除消息隊列中的消息 詳細介紹:http://blog.csdn.net/sun927/article/details/43001231                 http://www.cnblogs.com/zhangming-blog/articles/6101886.html

在源碼中查看得知:用法有handler.removeCallbacksAndMessages(null);
Android HandlerThread的用法   handler.getLooper().quit();)

(4)線程造成的記憶體泄漏 錯誤示例 非同步任務和Runnable都是一個匿名內部類,因此它們對當前Activity都有一個隱式引用。如果Activity在銷毀之前,任務還未完成, 那麼將導致Activity的記憶體資源無法回收,造成記憶體泄漏 解決方案 使用 靜態內部類,避免了Activity的記憶體資源泄漏,當然在Activity銷毀時候也應該取消相應的任務AsyncTask::cancel(),避免任務在後臺執行浪費資源 線程終結方法:http://blog.csdn.net/zhanjichun_2008/article/details/6612980

AsyncTask終結方式:http://blog.csdn.net/nnmmbb/article/details/53669177

(5)資源未關閉造成的記憶體泄漏 錯誤示例 對於使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源的使用,應該在Activity銷毀時及時關閉或者註銷,否則這些資源將不會被回收,造成記憶體泄漏 1、registerReceiver(r,filter);unregisterReceiver(r); 2、 getContentResolver().registerContentObserver(MyService.URI, false, myContentObsever);unregisterContentObserver() 3、IO.close() 4、cursor.close(); 5、  bitmap.recycle();   解決方案 在Activity銷毀時及時關閉或者註銷 (6)使用了靜態的Activity和View(很少見到) 錯誤示例 解決方案 應該及時將靜態的應用 置為null,而且一般不建議將View及Activity設置為靜態   (7)註冊了系統的服務,但onDestory未註銷 錯誤示例 解決方案

//不需要用的時候記得移除監聽

(8)不需要用的監聽未移除會發生記憶體泄露 錯誤示例 解決方案 Tip:tv.setOnClickListener();//監聽執行完回收對象,不用考慮記憶體泄漏 tv.getViewTreeObserver().addOnWindowFocusChangeListene,add監聽,放到集合裡面,需要考慮記憶體泄漏 案例七和案例八總結:有註冊基本上都有取消註冊,有添加監聽就有取消監聽。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • “億牛雲爬蟲代理IP”通過固定雲代理服務地址,建立專線網路鏈接,代理平臺自動實現毫秒級代理IP切換,保證了網路穩定性和速度,避免爬蟲客戶在代理IP策略優化上投入精力 獨享高匿家庭ip,支持隧道模式和api提取.高效穩定可測試基於Linux系統研發的平臺,自營線路,電信機房寬頻,私密家庭IP。平臺註冊 ...
  • --創表示例 create table testtab( id int primary key identity(20180,1), -- identity 是自增 (起始值,每次增值) -- primary key 主鍵唯一,且不能為空 name varchar(20), --欄位設置唯一值(un ...
  • SQL語句中生成UUID方法為UUID() 生成帶橫線UUID: select UUID() 形如:abaffaca-fd55-11e5-b3d0-d2c510923c15 生成32位不帶橫線UUID: select replace(UUID​(),'-','') 形如:804a9aa2fd5311 ...
  • Redis詳解 Redis的出現 NoSQL資料庫瞭解 在過去幾年中,NoSQL資料庫一度成為高併發、海量數據存儲解決方案的代名詞,與之相應的產品也如同雨後春筍般出現,然而在眾多產品中,能夠脫穎而出的卻 屈指可數,如Redis、MongoDB、BerkeleyDB和CouchDB等。由於每種產品所擁 ...
  • 前言 本文章主要是總結Linux的基礎操作以及一些簡單的概念~如果不熟悉的同學可下個Linux來玩玩(或者去買一個伺服器玩玩【學生版的不是很貴】),對於開發者來說,能使用Linux做一些基本的操作是必要的! 一、為什麼我們要學習Linux 相信大部分人的PC端都是用Windows系統的,那我們為什麼 ...
  • 好久沒做rac,最近要做架構梳理,這裡針對Oracle常用的名詞縮寫,這裡做個記錄,希望對大家有所幫助。 ...
  • 操作環境:Centos 問 題:The table 'XXX' is full !!! 當碰到此資料庫報錯提示的時候,,, 我,,,有點懵,,, 登錄伺服器查看,,發現 我了個去,,我絕不承認這個伺服器是我搭的,,(手動滑稽X2) MySQL資料庫的位置放到了分區/dev/mapper/centos ...
  • 本文說明瞭redis的基本用法,python與redis交互以及與mysql交互使用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...