現在真實測試結果:
1,為了搞清楚每個應用程序在Android系統中最多可分配多少內存空間,我們使用了真機進行測試,測試機型為魅族MX4 Pro,3G內存。
測試方法是直接申請一塊較大的內存空間,看應用程序在最多申請多大的內存空間時會崩潰。
結果:(1)未設定屬性android:largeheap = "true"時,可以申請到的最大內存空間為221M。
(2)設定屬性android:largeheap = "true"時, 可以申請的最大內存空間為478M,是原來的兩倍多一些。
網上有網友提出可申請到的最大內存空間與手機配置有關,以后會加以驗證。
2.實測,不准確, 准確的說話是 google原生OS的默認值是16M,但是各個廠家的OS會對這個值進行修改。
比如本人小米2S為例,這個值應該是96M。
Runtime rt=Runtime.getRuntime();
long maxMemory=rt.maxMemory();
log.i("maxMemory:",Long.toString(maxMemory/(1024*1024)));
這個可以直接得到app可使用的最大memory size算出來是MB, 獲得的是heapgrowthlimit
先看機器的內存限制,在/system/build.prop文件中:
heapgrowthlimit就是一個普通應用的內存限制,用ActivityManager.getLargeMemoryClass()獲得的值就是這個。
而heapsize是在manifest中設置了largeHeap=true 之后,可以使用的最大內存值
結論就是,設置largeHeap的確可以增加內存的申請量。但不是系統有多少內存就可以申請多少,而是由dalvik.vm.heapsize限制。
你可以在app manifest.xml加 largetHeap=true
可以申請較多的記憶體 ,但還是有機會爆掉.
<application
.....
android:label="XXXXXXXXXX"
android:largeHeap="true">
.......
</application>
cat /system/build.prop //讀取這些值
getprop dalvik.vm.heapsize //如果build.prop里面沒有heapsize這些值,可以用這個抓取默認值
setprop dalvik.vm.heapsize 256m //設置
----------------------- build.prop 部分內容 ---------------------
dalvik.vm.heapstartsize=8m
dalvik.vm.heapgrowthlimit=96m
dalvik.vm.heapsize=384m
dalvik.vm.heaputilization=0.25
dalvik.vm.heapidealfree=8388608
dalvik.vm.heapconcurrentstart=2097152
ro.setupwizard.mode=OPTIONAL
ro.com.google.gmsversion=4.1_r6
net.bt.name=Android
dalvik.vm.stack-trace-file=/data/anr/traces.txt
最早的說法:
1、APP默認分配內存大小
在Android里,程序內存被分為2部分:native和dalvik,dalvik就是我們普通的Java使用內存,也就是我們上一篇文章分析堆棧的時候使用的內存。我們創建的對象是在這里面分配的,對於內存的限制是 native+dalvik 不能超過最大限制。android程序內存一般限制在16M,也有的是24M(早期的Android系統G1,就是只有16M)。具體看定制系統的設置,在Linux初始化代碼里面Init.c,可以查到到默認的內存大小。有興趣的朋友,可以分析一下虛擬機啟動相關代碼。這塊比較深入,目前我也沒時間去分析,后面有空會去鑽研一下。
gDvm.heapSizeStart = 2 * 1024 * 1024; // heap初始化大小為2M
gDvm.heapSizeMax = 16 * 1024 * 1024; // 最大的heap為16M
2、Android的GC如何回收內存
Android的一個應用程序的內存泄露對別的應用程序影響不大。為了能夠使得Android應用程序安全且快速的運行,Android的每個應用程序都會使用一個專有的Dalvik虛擬機實例來運行,它是由Zygote服務進程孵化出來的,也就是說每個應用程序都是在屬於自己的進程中運行的。Android為不同類型的進程分配了不同的內存使用上限,如果程序在運行過程中出現了內存泄漏的而造成應用進程使用的內存超過了這個上限,則會被系統視為內存泄漏,從而被kill掉,這使得僅僅自己的進程被kill掉,而不會影響其他進程(如果是system_process等系統進程出問題的話,則會引起系統重啟)。
做應用開發的時候,你需要了解系統的GC(垃圾回收)機制是如何運行的,Android里面使用有向圖作為遍歷回收內存的機制。Java將引用關系考慮為圖的有向邊,有向邊從引用者指向引用對象。線程對象可以作為有向圖的起始頂點,該圖就是從起始頂點開始的一棵樹,根頂點可以到達的對象都是有效對象,GC不會回收這些對象。如果某個對象 (連通子圖)與這個根頂點不可達(注意,該圖為有向圖),那么我們認為這個(這些)對象不再被引用,可以被GC回收。
因此對於我們已經不需要使用的對象,我們可以把它設置為null,這樣當GC運行的時候,就好遍歷到你這個對象已經沒有引用,會自動把該對象占用的內存回收。我們沒法像C++那樣馬上釋放不需要的內存,但是我們可以主動告訴系統,哪些內存可以回收了。
3、查看應用內存使用情況
下面我們看看如何在開發過程中查看我們程序運行時內存使用情況。我們可以通過ADB的一個命令查看:
//$package_name:應用包名
//$pid:應用進程ID,可以用PS命令查看
adb shell dumpsys meminfo $package_name or $pid
上面是我使用包名查看Gallery例子的內存使用情況圖,里面信息很多,不過我們主要關注的是native和Davilk的使用情況。(Android2.X和Android4.X查看的信息排序是不一樣的,內容差不多,不過排布有差異,我上面是4.0的截圖)
Android底層內核是基於Linux的,而Linux里面相對Window來說,有一點很特別的是,會盡量使用系統內存加載一些緩存數據或者進程間共享數據。Linux本着不用白不用的原則,會盡量使用系統內存,加快我們應用的運行速度。當然,如果我們期待某個需要大內存的應用,系統也能馬上釋放出一定的內存使用,這是系統內部調度實現。因此嚴格來說,我們要准備計算Linux下某個進程內存大小比較困難。 因為有paging out to disk(換頁),所以如果你把所有映射到進程的內存相加,它可能大於你的內存的實際物理大小。
dalvik:是指dalvik所使用的內存。
native:是被native堆使用的內存。應該指使用C\C++在堆上分配的內存。
other:是指除dalvik和native使用的內存。但是具體是指什么呢?至少包括在C\C++分配的非堆內存,比如分配在棧上的內存。puzlle!
Pss:它是把共享內存根據一定比例分攤到共享它的各個進程來計算所得到進程使用內存。網上又說是比例分配共享庫占用的內存,也就是上面所說的進程共享問題。
PrivateDirty:它是指非共享的,又不能換頁出去(can not be paged to disk )的內存的大小。比如Linux為了提高分配內存速度而緩沖的小對象,即使你的進程結束,該內存也不會釋放掉,它只是又重新回到緩沖中而已。
SharedDirty:參照PrivateDirty我認為它應該是指共享的,又不能換頁出去(can not be paged to disk )的內存的大小。比如Linux為了提高分配內存速度而緩沖的小對象,即使所有共享它的進程結束,該內存也不會釋放掉,它只是又重新回到緩沖中而已。
上面針對meminfo里面的信息給出解析,這些很多我是參考了網上一些文章,所以如果有理解不到位的,歡迎各位指出。
4、程序中獲取內存信息
通過ActivityManager獲取相關信息,下面是一個例子代碼:
privatevoid displayBriefMemory()
{
final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(info);
Log.i(tag,"系統剩余內存:"+(info.availMem >> 10)+"k");
Log.i(tag,"系統是否處於低內存運行:"+info.lowMemory);
Log.i(tag,"當系統剩余內存低於"+info.threshold+"時就看成低內存運行");
}
另外通過Debug的getMemoryInfo(Debug.MemoryInfo memoryInfo)可以得到更加詳細的信息。跟我們在ADB Shell看到的信息一樣比較詳細。
5、總結
今天主要是分析了如何獲取我們應用的內存使用情況信息,關於這方面的信息,其實還有其他一些方法。另外還介紹APP應用的默認內存已經Android的GC回收,不過上面只是很淺薄地分析了一下,讓大家有個印象。這些東西真要深入分析得花不少精力。因為我們的目的只是解決OOM問題,所以目前沒打算深入分析,后面有時間進行Android系統分析的時候,我們再深入分析。下一次我們用以前寫的Gallery例子講解如何避免OOM問題,以及內存優化方法。
總述
Android應用程序被限制了內存使用上限,一般為16M或24M(具體看系統設置),當應用的使用內存超過這個上限時,就會被系統認為內存泄漏,被kill掉。