BitmapFactory.decodeResource和BitmapFactory.decodeStream,相信對於有過android app開發經驗的人來說都是很熟悉了。關於Bitmap的OOM問題,網上也有很多文章進行了分析,不少文章都說為避免OOM,最好使用BitmapFactory.decodeStream,但是具體說明原因的我至今沒有找到,所以趁著10.1期間有空,就調查了一番,希望結果對大家能有協助。
先來張時序圖,看了這張圖,估計很多問題都不用說明了:
下面做些說明:
1,函數externalBytesAvailable(...)的記憶體計算方法詳細請參見文章《Android Bitmap記憶體限制》;
2,Bitmap.createScaledBitmap時可能會對Bitmap進行縮放,縮放所使用的Options請參見下面這段代碼:
[java] view plaincopy
- public static Bitmap decodeResourceStream(Resources res, TypedValue value,
- InputStream is, Rect pad, Options opts) {
-
- if (opts == null) {
- opts = new Options();
- }
-
- if (opts.inDensity == 0 && value != null) {
- final int density = value.density;
- if (density == TypedValue.DENSITY_DEFAULT) {
- opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
- } else if (density != TypedValue.DENSITY_NONE) {
- opts.inDensity = density;
- }
- }
-
- if (opts.inTargetDensity == 0 && res != null) {
- opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
- }
-
- return decodeStream(is, pad, opts);
- }
當放大時,會加大造成OOM的可能性;
3,BitmapFactory.decodeResource比起BitmapFactory.decodeStream來說,在沒有參數Options opts的情況下,確實是多佔用了記憶體,因為多了BitmapFactory.finishDecode這一步,這裡多了一個Bitmap.createScaledBitmap操作;
4,關於使用BitmapFactory.decodeResource和BitmapFactory.decodeStream的效率對比,大家可以參見文章《Android 記憶體最佳化測試》
5,關於文章《Android 記憶體最佳化測試》提到的使用BitmapDrawable是最節省記憶體的方法,原因是frameworks\base\core\java\android\content\res\Resources.java對Bitmap做了緩衝處理,文中所有的array其實都是指向同一個Bitmap,這一點也可以通過Bitmap.toString的輸出資訊來證明。
備忘:時序圖看不清楚的,可以到http://download.csdn.net/detail/imyfriend/4617329下載原圖。
上篇文章談到了Bitmap的產生,現在說說Bitmap的釋放,要不總是有種沒說完的感覺。
Bitmap的釋放相對來說,比較簡單,還是先上張時序圖吧!
一些說明:
1,AndroidPixelRef的設定是在Bitmap產生的GraphicsJNI::setJavaPixelRef裡完成的,這裡可以參見文章《Bitmap的產生流程之BitmapFactory.decodeResource VS BitmapFactory.decodeStream》。具體代碼如下:
[cpp] view plaincopy
- bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
- SkColorTable* ctable, bool reportSizeToVM) {
- ......
- SkPixelRef* pr = reportSizeToVM ?
- new AndroidPixelRef(env, addr, size, ctable) :
- new SkMallocPixelRef(addr, size, ctable);
-
-
- ......
- }
2,VMRuntime.trackExternalFree把Bitmap佔用的虛擬機器heap記憶體歸還。如果你有興趣的話,請具體參見dalvik\vm\native\dalvik_system_VMRuntime.c。