熟悉Android內(nèi)存分配機(jī)制的朋友都知道百揭,Android為每個(gè)進(jìn)程分配內(nèi)存時(shí),采用彈性的分配方式蜓席,即剛開始并不會(huì)給應(yīng)用分配很多的內(nèi)存器一,而是給每一個(gè)進(jìn)程分配一個(gè)“夠用”的內(nèi)存大小。
那Android到底為每個(gè)應(yīng)用分配多少內(nèi)存呢厨内?我們可以實(shí)際測(cè)試一下:
以本人手上的努比亞NX510J手機(jī)為例:
private void getMaxMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.e("MaxMemory:", Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.e("MemoryClass:", Long.toString(activityManager.getMemoryClass()));
Log.e("LargeMemoryClass:", Long.toString(activityManager.getLargeMemoryClass()));
}
輸出結(jié)果為:
06-06 15:27:22.740 11917-11917/com.suning.myapp E/MaxMemory:: 192
06-06 15:27:22.740 11917-11917/com.suning.myapp E/MemoryClass:: 192
06-06 15:27:22.740 11917-11917/com.suning.myapp E/LargeMemoryClass:: 512
把AndroidManifest.xml中的application標(biāo)簽加上
<application
...
android:largeHeap="true"
...>
...
</application>
輸出結(jié)果為:
06-06 15:32:06.168 21973-21973/com.suningtang.myapp E/MaxMemory:: 512
06-06 15:32:06.168 21973-21973/com.suningtang.myapp E/MemoryClass:: 192
06-06 15:32:06.168 21973-21973/com.suningtang.myapp E/LargeMemoryClass:: 512
可以看到祈秕,設(shè)置largeHeap為true時(shí), 通過rt.maxMemory();獲取的值為512M雏胃。
因此请毛,對(duì)于本人這臺(tái)手機(jī),系統(tǒng)正常分配的內(nèi)存最多為192M瞭亮;當(dāng)設(shè)置largeHeap時(shí)方仿,最多可申請(qǐng)512M。當(dāng)超過這個(gè)值時(shí)统翩,就會(huì)出現(xiàn)OOM了仙蚜。
這個(gè)值是在哪設(shè)置的呢?查看/system/build.prop文件內(nèi)容:
shell@NX510J:/ $ cat /system/build.prop | grep heap
dalvik.vm.heapsize=36m
dalvik.vm.heapstartsize=8m ----起始分配內(nèi)存
dalvik.vm.heapgrowthlimit=192m ---- 一般情況app申請(qǐng)的最大內(nèi)存 dalvik.vm.heapsize=512m ---- 設(shè)置largeheap時(shí)厂汗,App可用的最大內(nèi)存dalvik.vm.heaptargetutilization=0.75 ---- GC相關(guān)
dalvik.vm.heapminfree=512k
dalvik.vm.heapmaxfree=8m ----- GC機(jī)制相關(guān)
上面的標(biāo)注了各參數(shù)的含義委粉。
那ActivityManager的getMemoryClass()和getLargeMemoryClass()方法返回的的是哪里的值呢?
//ActivityManager.java
public int getMemoryClass() {
return staticGetMemoryClass();
}
/** @hide */
static public int staticGetMemoryClass() {
String vmHeapSize = SystemProperties.get("dalvik.vm.heapgrowthlimit", "");
if (vmHeapSize != null && !"".equals(vmHeapSize)) {
return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
}
return staticGetLargeMemoryClass();
}
/**
* Return the approximate per-application memory class of the current
* device when an application is running with a large heap. This is the
* space available for memory-intensive applications; most applications
* should not need this amount of memory, and should instead stay with the
* {@link #getMemoryClass()} limit. The returned value is in megabytes.
* This may be the same size as {@link #getMemoryClass()} on memory
* constrained devices, or it may be significantly larger on devices with
* a large amount of available RAM.
*
* <p>The is the size of the application's Dalvik heap if it has
* specified <code>android:largeHeap="true"</code> in its manifest.
*/
public int getLargeMemoryClass() {
return staticGetLargeMemoryClass();
}
/** @hide */
static public int staticGetLargeMemoryClass() {
String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");
return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length() - 1));
}
上面的源碼表明娶桦,getMemoryClass()和getLargeMemoryClass()方法最終讀取的仍然是dalvik.vm.heapgrowthlimit和dalvik.vm.heapsize的值贾节。而且匣掸,dalvik.vm.heapsize默認(rèn)值為16M,這也是解釋了google的原生OS默認(rèn)值是16M了氮双。而dalvik.vm.heapgrowthlimit和dalvik.vm.heapsize的值各個(gè)手機(jī)廠家的OS會(huì)對(duì)這個(gè)值進(jìn)行修改碰酝,所以存在差異。
在App中獲取內(nèi)存信息
我們?cè)趹?yīng)用中可以通過ActivityManager的MemoryInfo內(nèi)部類獲取內(nèi)存信息戴差,方法如下:
private void getMemoryInfo() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
manager.getMemoryInfo(info);
Log.e("Memory","系統(tǒng)總內(nèi)存:"+(info.totalMem / (10241024))+"M");
Log.e("Memory","系統(tǒng)剩余內(nèi)存:"+(info.availMem / (10241024))+"M");
Log.e("Memory","系統(tǒng)是否處于低內(nèi)存運(yùn)行:"+info.lowMemory );
Log.e("Memory","系統(tǒng)剩余內(nèi)存低于"+( info.threshold / (1024*1024))+"M時(shí)為低內(nèi)存運(yùn)行");
}