Android開發Bitmap在Native層與Java層內存的兩種生成方式


         忽略掉遙遠的Android2.2及之前版本,本文討論基於Android4.4,也適用於4.x版本。
         項目開發中遇到一個內存溢出問題,抓內存數據分析,發現有的bitmap在java層生成,佔用的Dalvik虛擬機堆棧,這也符合我當前粗略的認知,恕本人知識淺陋。原來研究內存,一直認爲Android2.2之後的各個版本Android中bitmap都是通過JNI回調到Java層,最後是在Java層真正new出來的bitmap(這個在本文最後取源碼做了說明)。可是抓到的信息發現了一個Native stack上的Bitmap,如下圖所示。


         然後查看資料和源碼發現,的確這個是在Native Stack上創建的,因爲它是調用BitmapFactory.decodeStream方法,創建出一個bitmap,decodeStream直接調用 JNI 的 nativeDecodeAsset() 來完成decode,這點不同於使用java層的createBitmap。所以這個是在Native層佔用的內存。

private static Bitmap readBitMap(Context context, int resId) {  
        BitmapFactory.Options opt = new BitmapFactory.Options();  
        opt.inPreferredConfig = Bitmap.Config.RGB_565;  
        opt.inPurgeable = true;  
        opt.inInputShareable = true;  
        // 獲取資源圖片  
        InputStream is = context.getResources().openRawResource(resId);  
        return BitmapFactory.decodeStream(is, null, opt);  
    }  
這裏代碼搬一下別人的代碼來說明,如何做就在Native層生成Bitmap了,如上代碼,Options需要設置兩個參數, inPurgeable 、inInputShareable爲true。其實看源碼分析,如果調用decodeStream方法,其實只要 inPurgeable 爲true就夠了,inInputShareable是默認爲true的,不過別的方法就需要雙雙爲ture,稍後源碼分析詳述此處。大家只要如上調用就可以讓bitmap在Native上了。具體性能會不會有影響,稍後我會寫幾個demo驗證一下。


         如圖就是源碼中的調用,圖爲BitmapFactory這個源碼中decodeStream方法的具體實現,我們可以看到是調用的Native方法,可能有人會問了如果走了else呢,其實else裏面的方法跟進去就會發現,也是做了一些處理後,調用nativeDecodeAsset來生成的bitmap。


說到這裏我們必須說一個重要的事情,大家千萬別以爲去調用Native方法就一定是在Native層佔用的內存,例如Bitmap.java中的createBitmap也是調用的JNI方法,但其實又反過來回調的Java中的New來做的生成操作。具體的這個地方,我會專門寫一篇文章來講Bitmap和BitmapFactory的源碼,從源碼中徹底分析一下爲什麼就是在Native中生成的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章