[Android]記憶體洩露總結
Java 中的記憶體分配簡介
Java 中的記憶體分配
主要是分三塊:
- 靜態儲存區:編譯時就分配好,在程式整個執行期間都存在。它主要存放靜態資料和常量。
- 棧區:當方法執行時,會在棧區記憶體中建立方法體內部的區域性變數,方法結束後自動釋放記憶體
- 堆區:通常存放 new 出來的物件。由 Java 垃圾回收器回收。
棧與堆的區別
棧記憶體用來存放區域性變數和函式引數等。它是先進後出的佇列,進出一一對應,不產生碎片,執行效率穩定高。當超過變數的作用域後,該變數也就無效了,分配給它的記憶體空間也將被釋放掉,該記憶體空間可以被重新使用。
堆記憶體用於存放物件例項。在堆中分配的記憶體,將由Java垃圾回收器來自動管理。在堆記憶體中頻繁的 new / delete 會造成大量記憶體碎片,使程式效率降低。
對於非靜態變數的儲存位置,我們可以粗暴的認為:
- 區域性變數位於棧中(其中引用變數指向的物件實體存在於堆中)。
- 成員變數位於堆中。因為它們屬於類,該類最終被new成物件,並作為一個整體儲存在堆中。
四種引用型別的介紹
GC釋放物件的根本原則是該物件不再被引用(強引用)。那麼什麼是強引用呢?
強引用(Strong Reference)
我們平常用的最多的就是強引用,如下:
1 2 | Personperson=newPerson(); |
JVM 寧可丟擲 OOM ,也不會讓 GC 回收具有強引用的物件。強引用不使用時,可以通過 obj = null 來顯式的設定該物件的所有引用為 null,這樣就可以回收該物件了。至於什麼時候回收,取決於 GC 的演算法,這裡不做深究(其實我也不會)。
軟引用(Soft Reference)
建立軟引用:
1 2 | SoftReference<String>softRef=newSoftReference<>(str); |
如果一個物件只具有軟引用,那麼在記憶體空間足夠時,垃圾回收器就不會回收它;如果記憶體空間不足了,就會回收這些物件的記憶體。只要垃圾回收器沒有回收它,該物件就可以被使用。
軟引用曾經常被用來作圖片快取,然而谷歌現在推薦用 LruCache 替代,因為 LRU 更高效。
In the past, a popular memory cache implementation was a SoftReference or WeakReference bitmap cache, however this is not recommended. Starting from Android 2.3 (API Level 9) the garbage collector is more aggressive with collecting soft/weak references which makes them fairly ineffective. In addition, prior to Android 3.0 (API Level 11), the backing data of a bitmap was stored in native memory which is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash. > 原文
大致意思是:因為在 Android 2.3 以後,GC 會很頻繁,導致釋放軟引用的頻率也很高,這樣會降低它的使用效率。並且 3.0 以前 Bitmap 是存放在 Native Memory 中,它的釋放是不受 GC 控制的,所以使用軟引用快取 Bitmap 可能會造成 OOM。
弱引用(Weak Reference)
建立弱引用:
1 2 | WeakReference<String>weakRef=newWeakReference<>(str); |
與軟引用的區別在於:只具有弱引用的物件擁有更短暫的生命週期。因為在 GC 時,一旦發現了只具有弱引用的物件,不管當前記憶體空間足夠與否,都會回收它的記憶體。不過,由於垃圾回收器是一個優先順序很低的執行緒,因此不一定會很快發現那些只具有弱引用的物件- -。
虛引用(PhantomReference)
(好像並沒有什麼用)
顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定物件的生命週期,也無法通過虛引用獲得物件例項。虛引用必須和引用佇列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個物件時,如果發現它還有虛引用,就會在回收物件的記憶體之前,把這個虛引用加入到與之關聯的引用佇列中。程式可以通過判斷引用佇列中是否存在該物件的虛引用,來了解這個物件是否將要被回收。
Android的垃圾回收機制簡介
Android 系統裡面有一個 Generational Heap Memory 模型,系統會根據記憶體中不同的記憶體資料型別分別執行不同的 GC 操作。
該模型分為三個區:
- Young Generation
- eden
- Survivor Space
- S0
- S1
- Old Generation
- Permanent Generation
Young Generation
大多數 new 出來的物件都放到 eden 區,當 eden 區填滿時,執行 Minor GC(輕量級GC),然後存活下來的物件被轉移到 Survivor 區(有 S0,S1 兩個)。 Minor GC 也會檢查 Survivor 區的物件,並把它們轉移到另一個 Survivor 區,這樣就總會有一個 Survivor 區是空的。
Old Generation
存放長期存活下來的物件(經過多次 Minor GC 後仍然存活下來的物件) Old Generation 區滿了以後,執行 Major GC(大型 GC)。
在Android 2.2 之前,執行 GC 時,應用的執行緒會被暫停,2.3 開始添加了併發垃圾回收機制。
Permanent Generation
存放方法區。一般存放:
- 要載入的類的資訊
- 靜態變數
- final常量
- 屬性、方法資訊
60 FPS
這裡簡單的介紹一下幀率的概念,以便於理解為什麼大量的 GC 容易引起卡頓。
App 開發時,一般追求介面的幀率達到60 FPS(60 幀/秒),那這個 FPS 是什麼概念呢?
- 10-12 FPS 時可以感受到動畫的效果;
- 24 FPS,可以感受到平滑連貫的動畫效果,電影常用幀率(不追求 60 FPS 是節省成本);
- 60 FPS,達到最流暢的效果,對於更高的FPS,大腦已經難以察覺區別。
Android 每隔 16 ms發出 VSYNC 訊號,觸發對 UI 的渲染(即每 16 ms繪製一幀),如果整個過程保持在 16 ms以內,那麼就會達到 60 FPS 的流暢畫面。超過了 16 ms就會造成卡頓。那麼如果在 UI 渲染時發生了大量 GC,或者 GC 耗時太長,那麼就可能導致繪製過程超過 16 ms從而造成卡頓(FPS 下降、掉幀等),而我們大腦對於掉幀的情況十分敏銳,因此如果沒有做好記憶體管理,將會給使用者帶來非常不好的體驗。
再介紹一下記憶體抖動的概念,本文後面可能會用到這個概念。
記憶體抖動:短時間內大量 new 物件,達到 Young Generation 的閾值後觸發GC,導致剛 new 出來的物件又被回收。此現象會影響幀率,造成卡頓。
記憶體抖動在 Android 提供的 Memory Monitor 中大概表現為這樣:
Android中常見的記憶體洩露及解決方案
集合類洩露
如果某個集合是全域性性的變數(比如 static 修飾),集合內直接存放一些佔用大量記憶體的物件(而不是通過弱引用存放),那麼隨著集合 size 的增大,會導致記憶體佔用不斷上升,而在 Activity 等銷燬時,集合中的這些物件無法被回收,導致記憶體洩露。比如我們喜歡通過靜態 HashMap 做一些快取之類的事,這種情況要小心,集合內物件建議採用弱引用的方式存取,並考慮在不需要的時候手動釋放。
單例造成的記憶體洩露
補充第二種解決方案:
在構造單例時不需要傳入 context,直接在我們的 Application 中寫一個靜態方法,方法內通過 getApplicationContext 返回 context,然後在單例中直接呼叫這個靜態方法獲取 context。
嗯原理上是一樣的。
非靜態內部類造成的記憶體洩露
基於那位同學的文章進行補充:
在 Java 中,非靜態內部類(包括匿名內部類,比如 Handler, Runnable匿名內部類最容易導致記憶體洩露)會持有外部類物件的強引用(如 Activity),而靜態的內部類則不會引用外部類物件。
非靜態內部類或匿名類因為持有外部類的引用,所以可以訪問外部類的資源屬性成員變數等;靜態內部類不行。
因為普通內部類或匿名類依賴外部類,所以必須先建立外部類,再建立普通內部類或匿名類;而靜態內部類隨時都可以在其他外部類中建立。
以上其實是 Java 基礎 0.0
在 Android 中最典型的非靜態內部類造成的記憶體洩露非 Handler 莫屬。有些同學寫 Handler 時經常這樣寫:
看見沒,Android 都提示你了這裡可能會發生記憶體洩露!
這裡可能有同學不明白為什麼,吶,這裡創建出來的匿名物件 Handler 會間接的持有外部類例項 Activity 的引用,而 Handler 可能會因為要處理耗時操作導致存活時間超過 Activity(handler 被 main Looper 持有),或者 Message 還未被處理,而 Message 會持有 handler 的引用。於是,在 Activity 退出時,其引用還是被 Handler 持有,導致 Activity 無法被及時回收,造成記憶體洩露,洩露的多了,你的 App 就…Boom!
身為準程式設計師怎能容忍這一坨黃色的警告?哥教你正確的 Handler 應該怎麼寫:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | publicclassMainActivityextendsActivity{ StaticHandler mHandler=newStaticHandler(this); staticclassStaticHandlerextendsHandler{ WeakReference<MainActivity>activityReference; StaticHandler(MainActivityactivity){ activityReference=newWeakReference<>(activity); } @Override publicvoidhandleMessage(Messagemsg){ MainActivityactivity=activityReference.get(); if(activity!=null){ activity.getTextView().setText("測試"); } } } } |
如上,通過弱引用持有 Activity 物件,在 Activity 中提供 get 方法讓 Handler 可以訪問它的成員變數。
But…你以為這樣就完了嗎?這樣雖然避免了 Activity 洩漏,不過 Looper 執行緒的訊息佇列中還是可能會有待處理的訊息,所以我們在 Activity 的 Destroy 時或者 Stop 時應該移除訊息佇列中的訊息(根據業務需求移除吧)。
1 2 3 4 5 6 | @Override protectedvoidonDestroy(){ super.onDestroy(); mHandler.removeCallbacksAndMessages(null); } |
另一種常見的 Thread 執行緒物件導致的記憶體洩露,原因也是這樣的。執行緒 Thread 物件的 run 任務未執行完之前,它是不會被釋放的,而我們經常在 Activity 中 new 一個執行緒來執行耗時任務,通常也都是通過匿名內部類的方法構造執行緒物件,因此非常容易導致 Activity 無法及時釋放。
WebView 的洩漏
Android 中的 WebView 存在很大的相容性問題,有些 WebView 甚至存在記憶體洩露的問題。所以通常根治這個問題的辦法是為 WebView 開啟另外一個程序,通過 AIDL 與主程序進行通訊, WebView 所在的程序可以根據業務的需要選擇合適的時機進行銷燬,從而達到記憶體的完整釋放。
AlertDialog 造成的記憶體洩露
1 2 3 4 5 6 7 8 | newAlertDialog.Builder(this) .setPositiveButton("Baguette",newDialogInterface.OnClickListener(){ @OverridepublicvoidonClick(DialogInterfacedialog,intwhich){ MyActivity.this.makeBread(); } }) .show(); |
DialogInterface.OnClickListener 的匿名實現類持有了 MainActivity 的引用;
而在 AlertDialog 的實現中,OnClickListener 類將被包裝在一個 Message 物件中(具體可以看 AlertController 類的 setButton 方法),而且這個 Message 會在其內部被複制一份(AlertController 類的 mButtonHandler 中可以看到),兩份 Message 中只有一個被 recycle,另一個(OnClickListener 的成員變數引用的 Message 物件)將會洩露!
解決辦法:
- Android 5.0 以上不存在此問題;
- Message 物件的洩漏無法避免,但是如果僅僅是一個空的 Message 物件,將被放入物件池作為後用,是沒有問題的;
- 讓 DialogInterface.OnClickListener 物件不持有外部類的強引用,如用 static 類實現;
- 在 Activity 退出前 dismiss dialog!
Drawable 引起的記憶體洩露
Android 在 4.0 以後已經解決了這個問題。這裡可以跳過。
當我們螢幕旋轉時,預設會銷燬掉當前的 Activity,然後建立一個新的 Activity 並保持之前的狀態。在這個過程中,Android 系統會重新載入程式的UI檢視和資源。假設我們有一個程式用到了一個很大的 Bitmap 影象,我們不想每次螢幕旋轉時都重新載入這個 Bitmap 物件,最簡單的辦法就是將這個 Bitmap 物件使用 static 修飾。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | privatestaticDrawablesBackground; @Override protectedvoidonCreate(Bundlestate){ super.onCreate(state); TextViewlabel=newTextView(this); label.setText("Leaks are bad"); if(sBackground==null){ sBackground=getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground); setContentView(label); } |
但是上面的方法在螢幕旋轉時有可能引起記憶體洩露,因為,當一個 Drawable 繫結到了 View 上,實際上這個 View 物件就會成為這個 Drawable 的一個 callback 成員變數,上面的例子中靜態的 sBackground 持有 TextView 物件的引用,而 TextView 持有 Activity 的引用。當螢幕旋轉時,Activity 無法被銷燬,這樣就產生了記憶體洩露問題。
該問題主要產生在 4.0 以前,因為在 2.3.7 及以下版本 Drawable 的 setCallback 方法的實現是直接賦值,而從 4.0.1 開始,setCallback 採用了弱引用處理這個問題,避免了記憶體洩露問題。
資源未關閉造成的記憶體洩露
例如
- BroadcastReceiver,ContentObserver 之類的沒有解除註冊啊;
- Cursor,Stream 之類的沒有 close 啊;
- 無限迴圈的動畫在 Activity 退出前沒有停止啊;
- 一些其他的該 release 的沒有 release,該 recycle 的沒有 recycle…等等。
總結
我們不難發現,大多數問題都是 static 造成的!
- 在使用 static 時一定要小心,關注該 static 變數持有的引用情況。在必要情況下使用弱引用的方式來持有一些引用。
- 在使用非靜態內部類時也要注意,畢竟它們持有外部類的引用。(高階一點的使用 RxJava 的同學在 subscribe 時也要注意 unSubscribe 哦)。
- 注意在生命週期結束時釋放資源。
- 使用屬性動畫時,不用的時候請停止(尤其是迴圈播放的動畫),不然會產生記憶體洩露(Activity 無法釋放)(View 動畫不會)。
幾種記憶體檢測工具的介紹
- Memory Monitor
- Allocation Tracker
- Heap Viewer
- LeakCanary
Memory Monitor
位於 Android Monitor 中(別告訴我你不知道!),該工具可以:
- 方便的顯示記憶體使用和 GC 情況;
- 快速定位卡頓是否和 GC 有關;
- 快速定位 Crash 是否和記憶體佔用過高有關;
- 快速定位潛在的記憶體洩露問題(記憶體佔用一直在增長);
- 但是不能準確的定位問題。
Allocation Tracker
該工具用途:
- 可以定位程式碼中分配的物件型別、大小、時間、執行緒、堆疊等資訊;
- 可以定位記憶體抖動問題;
- 配合 Heap Viewer 定位記憶體洩露問題(可以找出來洩露的物件是在哪建立的等等)。
使用方法: 在 Memory Monitor 中有個 Start Allocation Tracking 按鈕即可開始跟蹤 在點選停止跟蹤後會顯示統計結果。
Heap Viewer
該工具用於
- 顯示記憶體快照資訊;
- 每次 GC 後收集一次資訊;
- 查詢記憶體洩露的利器。
使用方法: 在 Memory Monitor 中有個 Dump Java Heap 按鈕,點選即可,在統計報告左上角選按 package 分類。配合 Memory Monitor 的 initiate GC(執行 GC)按鈕,可檢測記憶體洩露等情況。
LeakCanary
重要的事情說三遍:
1 2 3 4 | for(inti=0;i<3;i++){ System.out.println("檢測記憶體洩露的神器!"); } |
LeakCanary 具體使用不再贅述,自行 Google。
OOM 主要元凶:大胖子 Bitmap
首先強調一點,載入圖片屬於耗時操作請放到非 UI 執行緒進行!
Android 中載入圖片時一般是按每畫素佔 4 byte 來處理的,拿計算器算一下可以發現,如果原封不動的載入一張圖片是非常佔記憶體的!因此非常容易 OOM。
網上流行一種說法,是說圖片解碼後是存放在 Native Memory 中,圖片用完要呼叫 Bitmap.recycle() 方法來回收記憶體,實際上谷歌不推薦這樣做了,因為這樣非常容易引發一些別的問題,並且在 Android 3.0 (API 11)以後,解碼後的資料已經調整為儲存在 Dalvik heap 中,Dalvik 會自動回收記憶體。詳情見Managing Bitmap Memory
那如何優化 Bitmap 從而避免 OOM 或者記憶體抖動呢?這裡提供兩種思路:使用物件池和縮放 Bitmap。
使用物件池
在啟動時預先申請一塊記憶體給物件池使用。載入圖片時根據特定演算法,從物件池中找到要淘汰的 Bitmap 物件,將其記憶體騰出來給新圖片用,這樣每次載入圖片也不用去向 JVM 申請記憶體,也避免了啟動 GC 來騰出記憶體,可以有效防止記憶體抖動,提升載入效率。
還有另一種複用 Bitmap 的方式:
在 Android 中可以讓 BitmapOption 的 inBitmap 屬性指向當前某個已建立的 Bitmap 物件,後續在解碼時傳入這個 option 就可以複用這個 Bitmap 物件的記憶體空間(要求兩者畫素格式必須一樣,例如都是 ARGB8888。也可以按畫素格式建立不同的物件來複用)。
注意,這個 inBitmap 引數在 API 11-18 時,後續要解碼的圖片大小必須和當前這個 Bitmap 一模一樣,才能複用,否則後面的圖片就無法複用了。在 API 19 以後就沒這個限制了,只要後續 Bitmap 大小小於等於要複用的 Bitmap 即可。
對 Bitmap 進行縮放
Android 提供瞭如下幾種方法來縮放 Bitmap:
- createScaledBitmap() 傳入指定寬高即可,該方法缺陷是需要傳入一個已經載入完畢的 Bitmap 圖片。。。都載入完了還要你幹嘛?
- inSampleSize。該值只能是 2 的倍數或者 1。原理是解碼時根據這個值,如果是 1,就記錄每一個畫素的值。如果值為 2,Android 就從每 4 個畫素中取出兩個畫素記錄下來。
- 如果我們需要縮放的倍數不是 2 的倍數,即 inSampleSize 滿足不了需求時,可以考慮設定 BitmapOption 的 inScaled 為 true,同時設定 inDensity 和 inTargetDensity 屬性,這樣就可以指定想要的 Bitmap 為原來的任意分之一大小了。該演算法很複雜,如果原圖較大,那麼縮放載入時可能會耗時較長。可以和 inSampleSize 結合使用,用 inSampleSize 縮放,減小大小後,再用這個方法縮放 。
記憶體優化
我們主要從減少記憶體使用的角度來考慮這個問題:
- 使用更輕量的資料結構,如用 SpareArray 代替 HashMap;
- 多使用 Google 提供的工具類,他們往往比 Java 的工具類更輕量,優化更好;
- 避免在 onDraw 方法中建立物件,因為該方法會被頻繁呼叫;
- 使用物件池,範例:Message;
- 使用 LRUCache 進行快取;
- Bitmap 優化。記憶體複用,壓縮 inSampleSize inBitmap;
- 用 StringBuilder 進行拼接;
- 使用列舉時用 Android 提供的註解,不用 Java 的列舉。使用 Java 列舉會導致增加的 dex 檔案大小是定義為常量的 10 多倍,佔用記憶體也遠大於常量。不信你 Dump 一下看看就知道了!Android 提供了註解來優化列舉,使用方法如下:
- 避免自動拆裝箱。基本資料型別的包裝類佔用記憶體較大,如果不是特別需要包裝類的話,就不要用包裝類(可以從 Allocation Tracker 看到,Integer 要佔 16 位元組,而 int 只佔 4 個位元組)。這種情況主要出現在 HashMap 等集合中,這些集合的泛型規定了只能用包裝類,所以 get,put 等操作均會涉及到自動拆裝箱,在操作頻繁時可能會出現效能問題。
我們可以用 Android 中提供的一些容器來替代 Java 中的一些容器,比如:SparseBoolMap,SparseIntMap,SparseLongMap,LongSparseMap 等,以上這幾個容器的 key 都是集合名中的那個基本型別,value 都是 Object。他們都是用 ArrayMap 實現的,ArrayMap 會對 key 佔用空間進行壓縮,並且可以通過普通 for 迴圈進行遍歷( keyAt(i), valueAt(i) )這樣遍歷效率高於迭代器遍歷(foreach 底層就是迭代器)。在容器 size 小於 1000 或者巢狀 map 的情況下,適合用 Sparse 系列替換 HashMap。
HashMap 的資料結構如下:
可以看到,HaspMap 建立時直接申請了一些空間來存 key 的 hash 值,在 key 數量沒有佔滿這些空間時,就很浪費。我們再來看看 ArrayMap 的資料結構 :
可以看到,不存在空間浪費。
一個簡單的記憶體優化練習
由大頭鬼老師提供,專案地址:MemoryBugs,要求運用各種工具查詢潛在的記憶體效能問題。建議各位自己先 clone 下來練習(老油條們就不用啦),再繼續往下看,和我的對比一下。我做的也不是標準答案,如有遺漏或不對的地方,歡迎指正。
先裝到模擬器上,啟動,當點選按鈕跳轉到 ActivityB 時,LeakCanary 彈出通知,告訴我們 Activity 發生了記憶體洩露 。
很明顯,是 TextView 持有 MainActivity 引用造成的,最簡單的解決辦法就是取消 sTextView 的 static 關鍵字,那如果非要採用靜態的呢?
我們再用 Dump Heap 檢視一下,在 MainActivity 介面,Dump :
可以看到 ActivityB 數量是 0,MainActivity 數量 1 接下來我們啟動 ActivityB,然後點選 initiate GC 將 MainActivity 回收 。
可以看到 MainActivity 仍然沒有被回收。那麼該怎麼解決呢?一種方式是在 onDestroy 中手動釋放:
1 2 3 4 5 6 | @Override protectedvoidonDestroy(){ super.onDestroy(); sTextView=null; } |
還可以用過弱引用的方式持有 TextView。
1 2 | sTextView=newWeakReference<>((TextView)findViewById(R.id.tv_text)).get(); |
解決後在 ActivityB 介面我們 initial GC 一下,發現 MainActivity 被回收了 。
這裡 Handler 可能也會造成記憶體洩露,我們在開啟 ActivityB 時,儘快 initial GC(考驗手速的時刻!),然後 LeakCanary 就彈出了通知:
顯然這裡洩露了,我們改寫 Handler 為靜態內部類就 OK。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | privateMyHandler mHandler=newMyHandler(this); publicstaticclassMyHandlerextendsHandler{ privateWeakReference<MainActivity>mWeakReference; publicMyHandler(MainActivityactivity){ mWeakReference=newWeakReference<>(activity); } @Override publicvoidhandleMessage(Messagemsg){ super.handleMessage(msg); } } |
然後我們再點選 STARTALLOCATION 按鈕出現了,觀察 Memory Monitor,發現出現了記憶體抖動。 使用 Allocation Tracking 工具重複一遍,統計結果如圖 :
發現 MainActivity 裡有 20001 個物件,基本一半是 Rect 一半是 StringBuilder。。 這裡可以把重複建立物件的操作提取出來,用 StringBuffer 替代 String。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
mStringBuffer=newStringBuffer("-------: ");
for(inti=0;i<10000;i++){
if(mRect==null){//避免建立大量的 mRect
mRect=newRect(0,0,100,100);
}else{
mRect.right=100;
mRect.bottom=100;
}
mStringBuffer.append(mRect.width());//避免建立大量的String
System.out.println(mStringBuffer);
mStringBuffer.delete
相關推薦[Android]記憶體洩露總結Java 中的記憶體分配簡介 Java 中的記憶體分配 主要是分三塊: 靜態儲存區:編譯時就分配好,在程式整個執行期間都存在。它主要存放靜態資料和常量。棧區:當方法執行時,會在棧區記憶體中建立方法體內部的區域性變數,方法結束後自動釋放記憶體堆區:通常存放 new 出來的物件 Android記憶體洩露常見問題總結概念梳理 在介紹記憶體洩漏之前很有必要提及一下Android系統的垃圾回收機制。Java GC(Garbage Collection,垃圾收集,垃圾回收)機制,是Java與C++/C的主要區別之一,作為Java開發者,不需要專門編寫記憶體回收和垃圾清理 Android記憶體洩露分析一,記憶體洩露 記憶體洩露:一個不在被使用的物件被另一個存活著的物件引用,在這種情況下垃圾回收器會跳過他,因為這種引用關係足以讓該物件駐留在記憶體中,記憶體洩露是在組織垃圾回收器為未來的記憶體分配提供空間,這些洩露的物件一直佔據著記憶體,導致我們的堆記憶體空間變得更小。也加劇了垃圾回 轉載:Android 記憶體洩露分析實戰演練版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://mp.csdn.net/postedit/82736058 轉載自任玉剛微信推文,非常全面所以記錄下來 1. 記憶體洩露簡介 記憶體洩露,即Memory Leak,指程式中不再使用到的物件因某種原因從而無法被GC正常回 Qt 學習之記憶體洩露 總結一、簡介 Qt記憶體管理機制:Qt 在內部能夠維護物件的層次結構。對於可視元素,這種層次結構就是子元件與父元件的關係;對於非可視元素,則是一個物件與另一個物件的從屬關係。在 Qt 中,在 Qt 中,刪除父物件會將其子物件一起刪除。 C++中delete 和 new 必須 android記憶體洩露深入研究首先抄上百科 隱式記憶體洩漏:程式在執行過程中不停的分配記憶體,但是直到結束的時候才釋放記憶體。嚴格的說這裡並沒有發生記憶體洩漏,因為最終程式釋放了所有申請的記憶體。但是對於一個伺服器程式,需要執行幾天,幾周甚至幾個月,不及時釋放記憶體也可能導致最終耗盡系統的所有記憶體。所 Android記憶體洩露利器(hprof篇)set processName=com.sec.android.app.dialertab;android.process.acore;com.sec.android.provider.logsprovider 全方位帶你徹底搞懂Android記憶體洩露1Java記憶體回收方式 Java判斷物件是否可以回收使用的而是可達性分析演算法。 在主流的商用程式語言中(Java和C#),都是使用可達性分析演算法判斷物件是否存活的。 使用命令列檢測Android記憶體洩露首先我們用電腦連線裝置,用cmd執行adb的記憶體檢測的命令 adb shell dumpsys meminfo com.screening 後面的com.screening是包名,要改成自己的 執行後顯示的資訊 這裡面需要關心的有:HeapSi 效能優化篇---記憶體管理之Android記憶體洩露記憶體洩漏:當你不再需要某個例項後,但是這個物件卻仍然被引用,防止被垃圾回收。這個情況就叫做記憶體洩露(Memory Leak)。 常見洩漏場景: 1.Handler 導致的記憶體洩漏 12345678910111213141516171819202122 publ 瞭解關於Android記憶體洩露等相關問題的處理方式我們在開發過程中,不時會遇到一些記憶體洩露等問題,比如說,開啟一個Activity,會findViewById到一些需要的控制元件來進行ADUS等操作。。 而當我們在結束一些Activity或Fragment之後,之前findViewById到的一些控制元件仍然 Android記憶體洩露分析工具—Android Monitor記憶體洩露大家應該不會陌生了,通常是因為該被釋放的物件被佔用,不能及時對其釋放,導致GC無法正常回收。我們可以使用一些工具來監控和分析導致記憶體洩露的位置和原因。用Eclipse的同志應該都知道MAT(Memory Analysis Tools),Android ThreadLocal引起記憶體洩露總結我們都知道ThreadLocal能給每一個執行緒建立一個副本,確保多個執行緒訪問資源的安全性。但是ThreadLocal使用不當會造成記憶體洩漏。首先分析一下ThreadLocal記憶體洩漏原理。 ThreadLocal底層其實是一個ThreadLocalMa Android記憶體洩露分析簡要思路工作中遇到挺多需要分析記憶體洩露問題的情況,現在大致簡要寫下思路,等之後時間相對比較充裕再進行補充。 1.明白記憶體洩露的判斷依據? 個人總結為:持續增加,只增不減! 理解一下這8個字,配合幾個命令和工具來確定一下你的應用是否存在記憶體洩露問題,這是很關鍵的,如果一開始就判斷錯誤了 Android記憶體洩露檢測工具和實際開發中遇到的記憶體洩露問題解析介紹 記憶體洩露是平常開發中經常遇到的,有些時候稍不注意就會發生,而且還不易察覺,這就需要工具來幫助檢測。本文主要介紹記憶體檢測工具和我在開發中遇到的記憶體洩露問題和解決方案。 記憶體洩露的原理 具體的原理涉及到虛擬機器垃圾回收機制知識,這裡只為下文作 Android 記憶體洩漏總結(超級實用)Android 記憶體洩漏總結 記憶體管理的目的就是讓我們在開發中怎麼有效的避免我們的應用出現記憶體洩漏的問題。記憶體洩漏大家都不陌生了,簡單粗俗的講,就是該被釋放的物件沒有釋放,一直被某個或某些例項所持有卻不再被使用導致 GC 不能回收。最近自己閱讀了大量相 Android記憶體洩露場景分析原文地址:http://www.cnblogs.com/qianxudetianxia/p/3645106.html大部分內容來自以上原文,有的內容從別的部落格中整理而來Context作為最基本的上下文,承載著Activity,Service等最基本元件。當有物件引用到Act Android 記憶體洩露和效能檢測Android Studio的記憶體分析介面 一般分析記憶體洩露, 首先執行程式,開啟日誌控制檯,有一個標籤Memory ,我們可以在這個介面分析當前程式使用的記憶體情況, 一目瞭然, 我們再也不需要苦苦的在logcat中尋找記憶體的日誌了。圖中藍色區域,就是程式使用的 Android記憶體洩露案例和解析使用過長物件生命週期 靜態引用 靜態變數儲存在方法區,在類載入的時候被載入,除非類被解除安裝了,或者他會一直存活,直到App程序銷燬,也就是說靜態變數的生命期等於整個程序的生命期。 private Context mContext; Android記憶體洩露分析之StrictMode轉載請註明地址:http://blog.csdn.net/yincheng886337/article/details/50524709 StrictMode(嚴格模式)使用 StrictMode嚴 |