本文章主要转载另外一个博主的一些理论,
链接:http://blog.csdn.net/gemmem/article/details/8920039
一种流行的观点是这样的:
Bitmap是jni层创建的,所以它应该是分配到native heap上,并且为了解释bitmap容易导致OOM,提出了这样的观点:
native heap size + dalvik heapsize <= dalvik vm heapsize
详情请看:
http://devspirit.blog.163.com/blog/static/16425531520104199512427/
但是请大家看看图6,native heap size为159508KB,远远超过dalvik vm heapsize,所以,事实证明以上观点是不正确的。
正确的观点:
大家都知道,过多地创建bitmap会导致OOM异常,且native heapsize不受dalvik限制,所以可以得出结论:
Bitmap只能是分配在dalvik heap上的,因为只有这样才能解释bitmap容易导致OOM。
但是,有人可能会说,Bitmap确实是使用java native方法创建的啊,为什么会分配到dalvik 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中。
ps:
为啥会有人得出错误的结论呢?
在android 2.3和以前的版本,bitmap对象的像素数据都是分配在native heap中的,所以我们在调试过程中这部分内存是在java heap中看不到的,不过在android 3.0之后,bitmap对象就直接分配在java heap上了,这样便于调试和管理。因此在3.0之后我们可以复用bitmap的内存,而不必回收它,不过新的bitmap对象要大小和原来的一样,到了android 4.4之后,就只要高宽不超过原来的就行了。Bitmap是分配在dalvik heap上的,只有这样才能解释bitmap容易导致OOM。