做者:林冠宏 / 指尖下的幽灵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
中。