現象:在sdcard上存放一個特殊分辨率的JPEG圖片,比如1x10000。然後使用android自帶的圖庫應用程序去瀏覽該圖片。使用圖庫瀏覽圖片,會先生成縮略圖供用戶瀏覽。此時,圖庫應用程序會異常退出,如果可以看其log,會發現dalvik分配內存時發生內存溢出。但是如果你使用別的圖片查看工具,不去生成縮略圖,直接打開該圖片,則不會發生異常。
分析:經過分析,發現google在做縮略圖時,有一處錯誤。Google設定所有縮略圖的分辨率都是96x96。以此爲目標,然後根據原始圖片的分辨率和目標圖片來計算縮放因子。相關函數在文件ThumbnailUtils.java中,其路徑爲:
/framework/base/media/java/android/media/ThumbnailUtils.java
函數具體定義爲:
/**
* Creates a centered bitmap of the desired size.
*
* @param source original bitmap source
* @param width targeted width
* @param height targeted height
* @param options options used during thumbnail extraction
*/
public static Bitmap extractThumbnail(
Bitmap source, int width, int height, int options) {
if (source == null) {
return null;
}
float scale;
if (source.getWidth() < source.getHeight()) {
scale = width / (float) source.getWidth();
} else {
scale = height / (float) source.getHeight();
}
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
Bitmap thumbnail = transform(matrix, source, width, height,
OPTIONS_SCALE_UP | options);
return thumbnail;
}
如果原始圖片的分辨率爲1600x1200,計算出來的scale爲:
scale = 96 / 1200 = 0.08
所需要的memory大小爲:1600*0.08 * 1200*0.08 * 2 = 24Kbyte
如果原始圖片的分辨率爲1x10000,計算出來的scale爲:
Scale = 96 / 1 = 96
所需要的memory大小爲:1*96 * 10000*96 * 2 = 175Mbyte,
而其本身所需要的空間爲:1 * 10000 * 2 = 19Kbyte。
Dalvik爲每個進程設置了允許申請的memory大小,默認爲16M。175M的memory需要是任何系統都不能滿足的。
總結:google在處理scale時,應該是隻考慮了大圖像縮小的情況,而沒有考慮小圖象放大的情況,特別是寬需要放大,而高需要縮小(或相反)。爲了不讓圖庫應用程序異常退出,可以在這裏做一些限制,當其所需memory過大時,可以不去生成縮略圖。