其實主要是內存方面,內存管理是個永恆的話題!
1.從工具DDMS中,在Sysinfo的tab欄裡面有一個Memory usage的選項,通過USB連接Android設備以後很容易抓到圖。
在圖中可以看到系統隨時可以用的內存是Free和Buffers兩項,因為我抓圖的系統只有128M的內存,所以看上去這部分可用內存已經很少了。
2.通過Linux的/proc文件系統的meminfo來分析這個系統的內存使用情況更客觀。之所以這麼說,是因為通過這種方法可以繞開繁瑣的dalvik實現機制,以系統的層面來分析:
C:\Users\Administrator>adb shell
shell@android:/ $ cat /proc/meminfo
cat /proc/meminfo
MemTotal: 999008 kB
MemFree: 157532 kB
Buffers: 41308 kB
Cached: 319584 kB
SwapCached: 0 kB
Active: 488128 kB
Inactive: 167012 kB
Active(anon): 292356 kB
Inactive(anon): 3544 kB
Active(file): 195772 kB
Inactive(file): 163468 kB
Unevictable: 1520 kB
Mlocked: 13684 kB
HighTotal: 529408 kB
HighFree: 61680 kB
LowTotal: 469600 kB
LowFree: 95852 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 295816 kB
Mapped: 165768 kB
Shmem: 360 kB
Slab: 27752 kB
SReclaimable: 9524 kB
SUnreclaim: 18228 kB
KernelStack: 8232 kB
PageTables: 9628 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 499504 kB
Committed_AS: 5690380 kB
VmallocTotal: 540672 kB
VmallocUsed: 139020 kB
VmallocChunk: 98112 kB
shell@android:/ $
對於Linux系統來說,可以立即使用的內存是 MemFree+Buffers+Cache,
我們從DDMS中拿到的圖差很多。或者說Google隱藏了cache,沒有給我我想要的東西;Android系統為了加快系統的運行速度會在系統允許的情況下,大量的使用內存作為應用程序的cache。而當系統內存緊張的時候,會首先釋放cache的內存,
3、Android內存介紹:
在java開發過程中,是通過new來為對象分配內存的,而內存的釋放是由垃圾收集器(GC)來回收的,在開發的過程中,不需要顯式的去管理內存,java虛擬機會自動幫我們回收內存。但是這樣有可能在不知不覺中就會浪費了很多內存,最終導致java虛擬機花費很多時間去進行垃圾回收,更嚴重的是造成JVM的OOM。
4、APP占用的內存分哪些:
Android系統中的內存和linux系統一樣,存在著大量的共享內存。每個APP占內存會有私有和公共的兩部分:ShareDirty、PrivateDirty。Pss是考慮共享內存的內核計算尺度 — 基本上一個進程的每個內存頁面被按一個比率縮減,這個比率和同樣使用該頁面的其他進程的數量有關。理論上你可以累計所有進程的Pss占用量來檢查所有進程的內存占用量,也可以比較進程的Pss來大致發現進程各自的權重。PrivateDirty,它基本上是進程內不能被分頁到磁盤的內存,也不和其他進程共享。
手機中系統設置裡有可以查看正在運行的應用程序所占的內存,此處顯示的內存為該進程所占用的Total Pss。所以我們只需要查看Total Pss的值就可以知道該應用運行時所占的內存的大小。
5、如何查看一個APP占用的內存,查看內存大致上有三種方法:
1. 通過系統設置查看
在系統設置中->應用->正在運行->APP
優點:操作簡單
缺點:數值不准確,無法實時查看數值變化
2. 通過命令行查看
adb shell dumpsys meminfo yourpakagename
其中Pss對應的TOTAL值為內存所實際占用的值
優點:簡單方便,數據全面精確
缺點:無法實時查看內存占用
3. 通過系統API查看
首先通過activitymanager獲得正在運行的程序列表,找到所要獲取的程序的pid。
activitymanager.getRunningAppProcesses()
再通過memoryinfo[0].getTotalPss();方法獲得實際內存占用
Memoryinfo中還包括getTotalPrivateDirty和getTotalSharedDirty方法
優點:可拓展性高,可以通過程序實時查看內存的占用;數據全面精確
缺點:需要具有開發能力,入手較為困難,所以我們現在在測試內存的時候,是使用了內部自己研發的一款APP來監測內存的,這個APP目前可以實現實時監測並記錄數據結果,可以提供給開發者和測試者分析內存的數據支持。目前仍然屬於內測階段,以後有機會可以提供給大家使用。
四、內存洩漏
何為內存洩漏?內存洩漏也稱作“存儲滲漏”,用動態存儲分配函數動態開辟的空間,在使用完畢後未釋放,結果導致一直占據該內存單元,直到程序結束。
內存洩漏的實例:
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
for (int i = 0; i < 100; i++) {
ImageView img = new ImageView(MainActivity.this);
img.setImageResource(R.drawable.ic_launcher);
test.add(img);
}
}
});
其中test為靜態的List<ImageView>。這樣,如果一直點擊btn就會出現內存洩漏的情形。
我們如何去監測內存洩漏呢?
以上面內存洩漏的例子為測試Activity,當點擊按鈕後,會向一個靜態數組中添加圖片,這樣就形成了一個內存洩漏的場景。
進入測試Activity,在點擊按鈕前先記錄當前APP所占用的內存,然後點擊按鈕。等待操作執行完成後,進行一次GC,再查看APP所占用的內存。
返回後APP所占用的內存沒有明顯的回落,表明在代碼中可能存在內存洩漏的情況發生。
即:在執行某種操作後進行一次GC,內存沒有明顯的回落。此時即可以斷定代碼中可能存在內存洩漏。
檢測方法:
通過上文所用的三種方法去查看內存的使用情況
使用DDMS中的Heap:
1) 打開DDMS並打開Devices視圖和Heap視圖
2) 點擊選擇要監控的進程
3) 選中Devices視圖界面上的”update heap” 圖標
4) 點擊Heap視圖中的”Cause GC” 按鈕(相當於進行了一次GC的操作)
一般我們會觀察Data Object的Total值,正常情況下在每次GC後,這個值都會有明顯的回落並會穩定在一個范圍之內,說明代碼中沒有未被釋放的內存;若這個值在每次GC後沒有出現明顯的回落,則說明代碼中可能存在沒有被釋放的內存。
總述:內存不僅是性能測試時需要關注的,作為優秀的開發工程師更應該關注自己的代碼內存占用的情況,這樣可以盡量避免OOM的情況發生。要知道手機分配給每個進程的內存並不多,當系統內存不夠的時候會kill掉一些占內存高的進程,所以為了不被系統kill掉我們要盡可能的合理使用內存避免內存洩漏的情況發生。