做者:林冠宏 / 指尖下的幽靈java
掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8android
博客:http://www.cnblogs.com/linguanh/git
GitHub : https://github.com/af913337456/程序員
騰訊雲專欄: https://cloud.tencent.com/developer/user/1148436/activitiesgithub
前言: 站在巨人的肩膀上,總結此文。
web
maxMemory
獲取當前 APP 最大可以申請的內存,在 Java Heap 層次,下同。面試
totalMemory
獲取當前 APP 已經從系統拿到的內存,包含使用上了的和沒有用上的,由於通常申請會申請多一部分,它老是慢慢按須要從系統拿取ide
freeMemory
獲取當前 APP 拿到的內存中,還沒用上的,便是能夠被 gc 回收的。函數
計算此刻 APP 在Java Heap 層已經使用了的內存 usedMemory
:ui
usedMemory = totalMemory - freeMemory
複製代碼
在不一樣的 Android 系統版本中,OOM 的判斷是不同的。
通俗來講,OOM 是當前進程共申請的內存綜和超過一個限制,而被拋出。
專業來講,Android爲每一個進程設置Dalvik Heap Size閾值,這個閾值在不一樣的設備上會由於RAM大小不一樣而各有差別。若是APP想要分配的內存超過這個閾值,就會發生OOM。
Android 3.x之前
,Bitmap分配在Native heap中,而在3.x以後
,Bitmap分配在Dalvik或ART的Java heap中。
Android 2.x系統,當dalvik allocated + native allocated + 新分配的大小 >= dalvik heap 最大值時候就會發生OOM,也就是說在2.x系統中,考慮native heap對每一個進程的內存限制。
Android 3.x系統,廢除了native的計數器,相似bitmap的分配改到dalvik的java heap中申請,只要allocated + 新分配的內存 >= dalvik heap 最大值的時候就會發生OOM(art運行環境的統計規則仍是和dalvik保持一致),也就是說在3.x系統中,不考慮native heap對每一個進程的內存限制,native heap只會收到本機總內存(包括RAM以及SWAP區或分頁文件)的限制。
建立一個新的進程,那麼咱們就能夠把一些對象分配到新進程的heap上了,從而達到一個應用程序使用更多的內存的目的,固然,建立子進程會增長系統開銷,並且並非全部應用程序都適合這樣作,視需求而定。
建立子進程的方法:使用android:process標籤
3.X 後的系統 native heap的增加並不受dalvik vm heapsize的限制,只要RAM有剩餘空間,程序員能夠一直在native heap上申請空間,固然若是 RAM快耗盡,memory killer會殺進程釋放RAM。你們使用一些軟件時,有時候會閃退,就多是軟件在native層申請了比較多的內存致使的。好比,我就碰到過UC web在瀏覽內容比較多的網頁時閃退,緣由就是其native heap增加到比較大的值,佔用了大量的RAM,被memory killer殺掉了。
使用OpenGL textures等API,texture memory不受dalvik vm heapsize限制,這個我沒有實踐過。再好比Android中的GraphicBufferAllocator申請的內存就是顯存。
上面說了,不一樣的系統版本不一樣,那麼在 3.X 及其以後,爲何在 java heap 而不是在 native heap 。請看下面源碼。
主要的文件
framework/base/graphic/java/Android/graphics/BitmapFactory.java
framework/base/core/jni/Android/graphics/BitmapFactory.cpp
framework/base/core/jni/Android/graphics/Graphics.cpp
複製代碼
BitmapFactory.java 裏面有幾個decode***方法用來建立bitmap,最終都會調用:
private staticnative Bitmap nativeDecodeStream(InputStream is, byte[] storage,Rect padding,Options opts);
複製代碼
而nativeDecodeStream()
會調用到BitmapFactory.cpp
中的deDecode
方法,最終會調用到Graphics.cpp
的createBitmap
方法。
createBitmap方法的實現:
jobjectGraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer,
boolisMutable, jbyteArray ninepatch, int density)
{
SkASSERT(bitmap);
SkASSERT(bitmap->pixelRef());
jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)),
buffer, isMutable, ninepatch,density);
hasException(env); // For the side effectof logging.
return obj;
}
複製代碼
從代碼中能夠看到bitmap
對象是經過env->NewOject(...)
建立的,到這裏疑惑就解開了,bitmap對象是虛擬機建立的,JNIEnv的NewOject方法返回的是java對象,並非native對象,因此它會分配到dalvik heap
中。