浅谈 maxMemory , totalMemory , freeMemory 和 OOM 与 native Heap

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

目录:

  • Java runtime 三个计算内存函数
  • OOM 的说法,为何大型游戏能申请那么多内存?
  • 如何绕过dalvikvm heap size的限制 ?
  • Bitmap分配在native heap仍是dalvik heap上?

1,Java runtime 三个计算内存函数:

maxMemory
获取当前 APP 最大可以申请的内存,在 Java Heap 层次,下同。面试

totalMemory
获取当前 APP 已经从系统拿到的内存,包含使用上了的和没有用上的,由于通常申请会申请多一部分,它老是慢慢按须要从系统拿取ide

freeMemory
获取当前 APP 拿到的内存中,还没用上的,便是能够被 gc 回收的。函数

计算此刻 APP 在Java Heap 层已经使用了的内存 usedMemoryui

usedMemory = totalMemory - freeMemory

复制代码

2,OOM 的说法,为何大型游戏能申请那么多内存?

在不一样的 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区或分页文件)的限制。

这也是为何有些APP(好比大型游戏)能够超过 Dalvik Heap Size 这个值?那是由于Java内存又分为Java Heap和Native Heap,3.X 后 Native Heap是不受该值约束的。像C/C++的内存都是在Native Heap中分配的。另外Bitmap是在Java Heap中分配的,咱们开发过程当中常常遇到由Bitmap引发的OOM,这就是一个例子。

3,如何绕过dalvikvm heap size的限制 ?

  • 建立子进程,上面说了,内存分配按进程来。再使用进程通信

建立一个新的进程,那么咱们就能够把一些对象分配到新进程的heap上了,从而达到一个应用程序使用更多的内存的目的,固然,建立子进程会增长系统开销,并且并非全部应用程序都适合这样作,视需求而定。

建立子进程的方法:使用android:process标签

  • 按不一样的系统版本,使用 jni 在native heap上申请空间(推荐使用)

3.X 后的系统 native heap的增加并不受dalvik vm heapsize的限制,只要RAM有剩余空间,程序员能够一直在native heap上申请空间,固然若是 RAM快耗尽,memory killer会杀进程释放RAM。你们使用一些软件时,有时候会闪退,就多是软件在native层申请了比较多的内存致使的。好比,我就碰到过UC web在浏览内容比较多的网页时闪退,缘由就是其native heap增加到比较大的值,占用了大量的RAM,被memory killer杀掉了。

  • 使用显存(操做系统预留RAM的一部分做为显存)

使用OpenGL textures等API,texture memory不受dalvik vm heapsize限制,这个我没有实践过。再好比Android中的GraphicBufferAllocator申请的内存就是显存。

4,Bitmap分配在native heap仍是dalvik heap上?

上面说了,不一样的系统版本不一样,那么在 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.cppcreateBitmap方法。

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中。

相关文章
相关标签/搜索