安卓heap值在哪裡改變
A. 修改android手機的dalvik-heap的大小多少
修改的方法:
1. dalvik.vm.heapgrowthlimit的設置在 /system/build.prop中
2. adb remount / adb pull /system/build.prop
3. 修改build.prop文件,將dalvik.vm.heapgrowthlimit修改後,adb
pull /system/
4. chmod修改build.prop的許可權。這里要注意,我開始修改的是chmod 777,後來系統起不來。ll
查看system/下文件許可權,發現時744。同理: chmod
744,發現就 OK了。原來許可權給高了還不行。
B. Android內存優化三:內存泄漏檢測與監控
Android內存優化一:java垃圾回收機制
Android內存優化二:內存泄漏
Android內存優化三:內存泄漏檢測與監控
Android內存優化四:OOM
Android內存優化五:Bitmap優化
Memory Profiler 是 Profiler 中的其中一個版塊,Profiler 是 Android Studio 為我們提供的性能分析工具,使用 Profiler 能分析應用的 CPU、內存、網路以及電量的使用情況。
進入了 Memory Profiler 界面。
點擊 Record 按鈕後,Profiler 會為我們記錄一段時間內的內存分配情況。
在內存分配面板中,通過拖動時間線來查看一段時間內的內存分配情況
通過搜索類或者報名的方式查看對象的使用情況
使用Memory Profiler 分析內存可以查看官網: 使用內存性能分析器查看應用的內存使用情況
對於內存泄漏問題,Memory Profiler 只能提供一個簡單的分析,不能夠確認具體發生問題的地方。
而 MAT 就可以幫我們做到這一點,它是一款功能強大的 Java 堆內存分析工具,可以用於查找內存泄漏以及查看內存消耗情況。
as 生成hprof文件無法被mat識別,需要進行轉換
使用hprof-conv進行轉換,hprof-conv位於sdkplatform-tools
ps:as導出hprof前最好先gc幾次,可排除一些干擾
Histogram 可以列出內存中的對象,對象的個數以及大小; Dominator Tree 可以列出那個線程,以及線程下面的那些對象佔用的空間; Top consumers 通過圖形列出最大的object; Leak Suspects 通過MA自動分析泄漏的原因。
Shallow Heap就是對象本身佔用內存的大小,不包含其引用的對象內存,實際分析中作用不大。常規對象(非數組)的ShallowSize由其成員變數的數量和類型決定。數組的shallow size有數組元素的類型(對象類型、基本類型)和數組長度決定。對象成員都是些引用,真正的內存都在堆上,看起來是一堆原生的byte[], char[], int[],對象本身的內存都很小。
Retained Heap值的計算方式是將Retained Set(當該對象被回收時那些將被GC回收的對象集合)中的所有對象大小疊加。或者說,因為X被釋放,導致其它所有被釋放對象(包括被遞歸釋放的)所佔的heap大小。
Path To GC Roots -> exclude all phantim/weak/soft etc. references:查看這個對象的GC Root,不包含虛、弱引用、軟引用,剩下的就是強引用。從GC上說,除了強引用外,其他的引用在JVM需要的情況下是都可以 被GC掉的,如果一個對象始終無法被GC,就是因為強引用的存在,從而導致在GC的過程中一直得不到回收,因此就內存泄漏了。
List objects -> with incoming references:查看這個對象持有的外部對象引用
List objects -> with outcoming references:查看這個對象被哪些外部對象引用
使用對象查詢語言可以快速定位發生泄漏的Activity及Fragment
使用 MAT 來分析內存問題,效率比較低,為了能迅速發現內存泄漏,Square 公司基於 MAT 開源了 LeakCanary ,LeakCanary 是一個內存泄漏檢測框架。
集成LeakCanary後,可以在桌面看到 LeakCanary 用於分析內存泄漏的應用。
當發生泄漏,會為我們生成一個泄漏信息概覽頁,可以看到泄漏引用鏈的詳情。
LeakCanary 會解析 hprof 文件,並且找出導致 GC 無法回收實例的引用鏈,這也就是泄漏蹤跡(Leak Trace)。
泄漏蹤跡也叫最短強引用路徑,這個路徑是 GC Roots 到實例的路徑。
LeakCanary 存在幾個問題,不同用於線上監控功能
線上監控需要做的,就是解決以上幾個問題。
各大廠都有開發線上監控方案,比如快手的 KOOM ,美團的 Probe ,位元組的 Liko
快手自研OOM解決方案KOOM今日宣布開源
總結一下幾點:
通過無性能損耗的 內存閾值監控 來觸發鏡像採集。將對象是否泄漏的判斷延遲到了解析時
利用系統內核COW( Copy-on-write ,寫時復制)機制,每次mp內存鏡像前先暫停虛擬機,然後fork子進程來執行mp操作,父進程在fork成功後立刻恢復虛擬機運行,整個過程對於父進程來講總耗時只有幾毫秒,對用戶完全沒有影響。
C. 如何修改Android應用程序能夠使用的默認最大內存值
解決辦法:
1. 修改dalvik/vm/Init.c:
static void setCommandLineDefaults()
* TODO: base these on a system or application-specific default
*/
gDvm.heapSizeStart = 2 * 1024 * 1024; // Spec says 16MB; too big for us.
- gDvm.heapSizeMax = 16 * 1024 * 1024; // Spec says 75% physical mem
+ gDvm.heapSizeMax = 32 * 1024 * 1024; // Spec says 75% physical mem
gDvm.stackSize = kDefaultStackSize;
2. 修改frameworks/base/core/jni/AndroidRuntime.cpp:
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
//options[curOpt++].optionString = "-verbose:class";
strcpy(heapsizeOptsBuf, "-Xmx");
- property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
+ property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "32m");
//LOGI("Heap size: %s", heapsizeOptsBuf);
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
D. Android App內存優化
內存優化就是對內存問題的一個預防和解決,做內存優化能讓應用掛得少、活得好和活得久。
掛的少:
「掛」指的是 Crash,內存問題導致 Crash 的具體表現就是內存溢出異常 OOM。
活得好:
活得好指的是使用流暢,Android 中造成界面卡頓的原因有很多種,其中一種就是由內存問題引起的。內存問題之所以會影響到界面流暢度,是因為垃圾回收(GC,Garbage Collection),在 GC 時,所有線程都要停止,包括主線程,當 GC 和繪制界面的操作同時觸發時,繪制的執行就會被擱置,導致掉幀,也就是界面卡頓。
活得久:
活得久指的是我們的應用在後台運行時不會被幹掉。Android 會按照特定的機制清理進程,清理進程時優先會考慮清理後台進程。清理進程的機制就是LowMemoryKiller。在 Android 中不同的進程有著不同的優先順序,當兩個進程的優先順序相同時,低殺會優先考慮幹掉消耗內存更多的進程。也就是如果我們應用佔用的內存比其他應用少,並且處於後台時,我們的應用能在後台活下來,這也是內存優化為我們應用帶來競爭力的一個直接體現。
內存佔用是否越少越好?
當系統 內存充足 的時候,我們可以多用 一些獲得更好的性能。當系統 內存不足 的時候,我們希望可以做到 」用時分配,及時釋放「。內存優化並不能一刀切。
我們都知道,應用程序的內存分配和垃圾回收都是由Android虛擬機完成的,在Android 5.0以下,使用的是Dalvik虛擬機,5.0及以上,則使用的是ART虛擬機。
Android虛擬機Dalvik和ART
1、內存區域劃分
詳細請看以下兩篇文章(建議全看):
java內存四大區_JVM內存區域劃分
Android 內存機制
2、內存回收
垃圾收集的標記演算法(找到垃圾):
垃圾收集演算法(回收垃圾):
引用類型:強引用、軟引用、弱引用、虛引用
對象的有效性=可達性+引用類型
JAVA垃圾回收機制-史上最容易理解看這一篇就夠了
Android:玩轉垃圾回收機制與分代回收策略
android中還存在低殺機制,這種情況屬於系統整機內存不足,直接把應用進程殺掉的情況。
Android後台殺死系列:LowMemoryKiller原理
1、內存溢出
系統會給每個App分配內存空間也就是heap size值,當app佔用的內存加上申請的內存超過這個系統分配的內存限額,最終導致OOM(OutOfMemory)使程序崩潰。
通過命令 getprop |grep dalvik.vm.heapsize 可以獲取系統允許的最大
注意:在設置了heapgrowthlimit的狀況下,單個進程可用最大內存為heapgrowthlimit值。在android開發中,若是要使用大堆,須要在manifest中指定android:largeHeap為true,這樣dvm heap最大可達heapsize。
關於heapsize & heapgrowthlimit
2、內存泄漏
Android系統虛擬機的垃圾回收是通過虛擬機GC機制來實現的。GC會選擇一些還存活的對象作為內存遍歷的根節點GC Roots,通過對GC Roots的可達性來判斷是否需要回收。內存泄漏就是 在當前應用周期內不再使用的對象被GC Roots引用,造成該對象無法被系統回收,以致該對象在堆中所佔用的內存單元無法被釋放而造成內存空間浪費,使實際可使用內存變小。簡言之,就是 對象被持有導致無法釋放或不能按照對象正常的生命周期進行釋放。
Android常見內存泄漏匯總
3、內存抖動
指的是在短時間內大量的新對象被實例化,運行時可能無法承載這樣的內存分配,在這種情況下就會導致垃圾回收事件被大量調用,影響到應用程序的UI和整體性能,最終可能導致卡頓和OOM。
常見情況:在一些被頻繁調用的方法內不斷地創建對象。例如在View 的onDraw方法內new 一些新的對象。
注意內存抖動也會導致 OOM,主要原因有如下兩點:
1、Android Studio Profiler
作用
優點
內存抖動問題處理實戰
理解內存抖動的概念的話,我們就能明白只要能找到抖動過程中所產生的對象及其調用棧,我們就能解決問題,剛好Android Studio 的Porfiler裡面的Memory工具就能幫我們記錄下我們操作過程中或靜止界面所產生的新對象,並且能清晰看到這些對象的調用棧。
選擇Profile 中 的Memory ,選擇 Record Java/Kotlin allocations,再點擊Record開始記錄, Record Java/Kotlin allocations 選項會記錄下新增的對象。
操作完成之後,點擊如圖所示的紅腦按鈕,停止記錄。
停止記錄後,我們就可以排序(點擊 Allocations可以排序)看看哪些對象或基本類型在短時間被頻繁創建多個,點擊這些新增的對象就可以看到它的完成的調用鏈了,進而就找找到導致內存抖動的地方在哪裡了。
2、利用DDMS 和 MAT(Memory Analyzer tool)來分析內存泄漏
我們利用工具進行內存泄漏分析主要是用對比法:
a.先打開正常界面,不做任何操作,先抓取一開始的堆文件。
b.一頓胡亂操作,回到原來操作前的界面。主動觸發一兩次GC,過10秒再抓取第二次堆文件。
c.通過工具對比,獲取胡亂操作後新增的對象,然後分析這些新增的對象。
DDMS作用:抓取堆文件,主動觸發GC。(其實也是可以用Android Studio 的Profile裡面的Memory工具來抓取堆文件的,但是我這邊在利用Profile 主動觸發gc 的時候會導致程序奔潰,也不知道是不是手機的問題,所以沒用Android Studio的Profiler)
MAT作用:對堆文件進行對比,找到多出的對象,找到對象的強引用調用鏈。
以下是詳細的過程:
步驟1.打開DDMS,選擇需要調試的應用,打開初始界面,點擊下圖的圖標(Dump Hprof File)先獲取一次堆文件。
步驟2.對應用隨便操作後,回到一開始的界面,先多觸發幾次GC ,點擊下圖的圖標(Cause Gc)來主動觸發GC,然後再次點擊 Dump Hprof File 圖標來獲取堆文件。
步驟3.通過Android Studio Profile 或者 DDMS mp 的堆文件無法在MAT 打開,需要藉助android sdk包下的一個工具hprof-conv.exe來轉換。
格式為 hprof-conv 舊文件路徑名 要轉換的名稱;
例如:hprof-conv 2022-04-13_17-54-40_827.hprof change.hprof
步驟4.把兩份堆文件導入MAT,然後選擇其中第二次獲取的堆文件,點擊 如圖所示的 Histogram查看。
步驟5.點擊下圖圖標,Compare To Another Heap Dump ,選擇另一份堆文件。
6.會得出下圖所示的 Hitogram 展示,我們主要看Objects 這一列。 如下圖所示 「+ 2」 則代表前面兩份堆文件對比,這個對象多了兩個,我們主要就是要分析這些多了出來,沒有被回收的對象。
7.加入我們從增加的對象中,看到了MainActivity ,則需要從一開始打開的Hitogram 展示裡面找到這個對象的調用棧。如下圖所示,搜索MainActivity
8.看到下圖所示解僱,然後滑鼠右鍵點擊下圖紅色圈圈著的MainActivity ,選擇 Merger Shortest Paths to Gc Roots ,再選擇 exclude all phantom/weak/soft etc.references ,就可以看到這個MainActivity 對象的強引用鏈,至此我們就可以找到MainActivity對象是被什麼引用導致無法回收了。
3、內存泄露檢測神器之LeakCanary(線下集成)
自行學習了解,接入簡單,使用簡單,基本可以解決大部分內存泄漏問題。
github地址 : https://github.com/square/leakcanary/
學習地址 : https://square.github.io/leakcanary/changelog/#version-22-2020-02-05
針對內存抖動的建議:
針對內存泄漏問題的建議:
針對內存溢出問題的建議(主要就是要減少內存佔用):
建議參考:
深入探索 Android 內存優化(煉獄級別)
對於 優化的大方向,我們應該優先去做見效快的地方,主要有以下三部分:內存泄漏、內存抖動、Bitmap。完善監控機制也是我們的重點,能幫助我們對內存問題快速分析和處理。
參考:
深入探索 Android 內存優化(煉獄級別)