Masalah OOM disebabkan oleh Bitmap
Pengenalan kepada bahagian ini:
Dalam bahagian sebelumnya, kita telah mempelajari penggunaan asas Bitmap, dan dalam bahagian ini kita akan membincangkan masalah OOM bagi Bitmap. Anda mungkin atau mungkin tidak menghadapi masalah OOM yang disebabkan oleh Bitmap dalam pembangunan sebenar Dalam bahagian ini kami akan Mari belajar tentang topik ini ~ Fahami apa itu OOM, sebab ia menyebabkan OOM, dan perbaiki masalah yang disebabkan oleh Bitmap Isu OOM~
1. Mengapa ia menyebabkan OOM?
Jawapan: Habis Ingatan (memori limpahan), kita semua tahu bahawa sistem Android akan memperuntukkan ruang kerja bebas untuk setiap APP. Atau peruntukkan mesin maya Dalvik yang berasingan supaya setiap APP boleh berjalan secara bebas tanpa menjejaskan satu sama lain! Dan Android untuk setiap satu Mesin maya Dalvik akan mempunyai had memori maksimum Jika memori yang diduduki pada masa ini ditambah dengan sumber memori yang kami gunakan melebihi had ini , sistem akan membuang ralat OOM! Di samping itu, jangan kelirukan ini dengan RAM Walaupun terdapat lebih daripada 1G memori yang tinggal dalam RAM, OOM masih akan berlaku! Jangan campurkan RAM (memori fizikal) dan OOM! Di samping itu, jika RAM tidak mencukupi, aplikasi akan dimatikan, bukan hanya OOM! Standard memori maksimum dalam Dalvik adalah berbeza untuk model yang berbeza Anda boleh menghubungi:
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); Log.e("HEHE","最大内存:" + activityManager.getMemoryClass());
untuk mendapatkan standard memori maksimum biasa, atau taip terus pada baris arahan:
adb shell getprop | grep dalvik.vm.heapgrowthlimit
Anda juga boleh membuka. kod sumber sistem /system/build.prop fail dan lihat maklumat dalam bahagian fail ini untuk mendapatkan:
dalvik.vm.heapstartsize=8m dalvik.vm.heapgrowthlimit=192m dalvik.vm.heapsize=512m dalvik.vm.heaptargetutilization=0.75 dalvik.vm.heapminfree=2m dalvik.vm.heapmaxfree=8m
Terdapat tiga kawasan yang kami bimbang: saiz awal memori timbunan bersaiz heapstartsize, dan penggunaan piawaian had pertumbuhan timbunan Timbunan terbesar Saiz memori, saiz timbunan menetapkan saiz memori timbunan maksimum untuk aplikasi menggunakan android:largeHeap!
Saya mencuba di sini piawaian peruntukan memori maksimum biasa untuk beberapa model:
Anda juga boleh mencubanya pada mesin anda sendiri~
Baiklah, mari kita berhenti bercakap mengenainya mengenai masalah OOM, kita akan berhenti di sini. Saya masih tidak boleh mengunyahnya sekarang... Mari lihat beberapa petua untuk mengelakkan Bitmap OOM!
2. Ringkasan petua untuk mengelakkan OOM disebabkan oleh Bitmap
1) Gunakan pengekodan jejak memori rendah
Seperti yang dinyatakan dalam bahagian sebelumnyaBitmapFactory.OptionsKelas ini, kita boleh menetapkan atribut inPreferredConfig,
Lalainya ialah Bitmap.Config.ARGB_8888, kita boleh menukarnya kepada Bitmap.Config.ARGB_4444
Bitmap.Config ARGB_4444: Setiap piksel menduduki empat bit, iaitu, A= 4, R =4, G=4, B=4, kemudian satu piksel menduduki 4+4+4+4=16 bit
Bitmap.Config ARGB_8888: Setiap piksel menduduki lapan bit, iaitu, A=8, R =8, G=8, B=8, kemudian satu piksel menduduki 8+8+8+8=32 bit
Secara lalai, ARGB_8888 digunakan, iaitu, satu piksel menduduki 4 bait!
2) Pemampatan imej
juga adalah BitmapFactory.Options Kami menetapkan faktor penskalaan melalui inSampleSize, contohnya, tulis 2, iaitu panjang dan lebar menjadi. 1/2 daripada yang asal, Gambar adalah 1/4 daripada saiz asal Jika anda tidak menskalakannya, tetapkan ia kepada 1! Tetapi ia tidak boleh dimampatkan secara membuta tuli, lagipun, nilai ini terlalu kecil. Jika tidak, gambar akan menjadi sangat kabur, dan kita perlu mengelakkan regangan dan mengubah bentuk gambar, jadi kita perlu mengira ini secara dinamik dalam program. Nilai inSampleSize yang sesuai, dan terdapat kaedah sedemikian dalam Pilihan: inJustDecodeBounds, tetapkan parameter ini kepada Selepas benar, decodeFiel tidak akan memperuntukkan ruang memori, tetapi boleh mengira panjang dan lebar imej asal, memanggil pilihan.outWidth/outHeight Dapatkan lebar dan tinggi imej, kemudian gunakan algoritma tertentu untuk mendapatkan yang sesuai inSampleSize, terima kasih atas kod yang disediakan oleh dewa jalanan - diambil dari blog Hongyang!
public static int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int width = options.outWidth; int height = options.outHeight; int inSampleSize = 1; if (width > reqWidth || height > reqHeight) { int widthRadio = Math.round(width * 1.0f / reqWidth); int heightRadio = Math.round(height * 1.0f / reqHeight); inSampleSize = Math.max(widthRadio, heightRadio); } return inSampleSize; }
Kemudian gunakan kaedah di atas:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 设置了此属性一定要记得将值设置为false Bitmap bitmap = null; bitmap = BitmapFactory.decodeFile(url, options); options.inSampleSize = computeSampleSize(options,128,128); options.inPreferredConfig = Bitmap.Config.ARGB_4444; /* 下面两个字段需要组合使用 */ options.inPurgeable = true; options.inInputShareable = true; options.inJustDecodeBounds = false; try { bitmap = BitmapFactory.decodeFile(url, options); } catch (OutOfMemoryError e) { Log.e(TAG, "OutOfMemoryError"); }
3 Kitar semula imej dalam masa
Jika sejumlah besar objek Bitmap dirujuk dan aplikasi tidak perlu Paparkan semua imej serentak. Objek bitmap yang tidak digunakan buat sementara waktu boleh Kitar semula dengan segera. Untuk beberapa senario di mana anda mengetahui dengan jelas penggunaan imej, anda boleh mengitar semula imej tersebut secara aktif, seperti imej pada halaman but, gunakan Apabila selesai, kitar semula, bingkai animasi, muatkan satu, lukis satu, dan lepaskan satu! Muatkan apabila digunakan, tetapkan batal atau kitar semula terus apabila tidak dipaparkan! Contohnya: imageView.setImageResource(0); Walau bagaimanapun, dalam beberapa kes, gambar tertentu mungkin berulang kali dimuatkan, dikeluarkan dan dimuat semula, dsb., yang tidak cekap...
4 Kaedah lain
Saya belum pernah menggunakan kaedah berikut. Jika anda belum pernah menggunakannya, anda boleh menyemak sendiri maklumat yang berkaitan:
1. Hanya urus sumber imej melalui rujukan SoftReference
Buat peta cincang SoftReference. Apabila menggunakan imej, semak dahulu sama ada peta cincang mempunyai rujukan lembut dan sama ada imej dalam rujukan lembut itu kosong. Jika ia kosong, muatkan imej ke dalam rujukan lembut dan tambahkannya pada peta cincang. Tidak perlu mengendalikan secara eksplisit kitar semula dan keluaran imej dalam kod, gc akan mengendalikan pengeluaran sumber secara automatik. Kaedah ini mudah dan praktikal untuk dikendalikan, dan boleh mengelakkan ketidakcekapan pemuatan berulang dan pelepasan kaedah sebelumnya ke tahap tertentu. Tetapi ia tidak cukup dioptimumkan.
Kod contoh:
private Map<String, SoftReference> imageMap = new HashMap<String, SoftReference>(); public Bitmap loadBitmap(final String imageUrl,final ImageCallBack imageCallBack) { SoftReference reference = imageMap.get(imageUrl); if(reference != null) { if(reference.get() != null) { return reference.get(); } } final Handler handler = new Handler() { public void handleMessage(final android.os.Message msg) { //加入到缓存中 Bitmap bitmap = (Bitmap)msg.obj; imageMap.put(imageUrl, new SoftReference(bitmap)); if(imageCallBack != null) { imageCallBack.getBitmap(bitmap); } } }; new Thread(){ public void run() { Message message = handler.obtainMessage(); message.obj = downloadBitmap(imageUrl); handler.sendMessage(message); } }.start(); return null ; } // 从网上下载图片 private Bitmap downloadBitmap (String imageUrl) { Bitmap bitmap = null; try { bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream()); return bitmap ; } catch (Exception e) { e.printStackTrace(); return null; } } public interface ImageCallBack{ void getBitmap(Bitmap bitmap); }
2. LruCache + kaedah caching sd
Bermula dari Android 3.1, pegawai juga menyediakan LruCache Perform cache pemprosesan apabila saiz Imej yang disimpan lebih besar daripada LruCache Jika nilai ditetapkan, gambar dengan penggunaan paling sedikit terkini akan dikitar semula, dan sistem akan melepaskan memori secara automatik!
Contoh penggunaan:
Langkah:
1) Mula-mula tetapkan saiz memori imej cache, saya tetapkan di sini ke memori telefon bimbit 1/8, Cara mendapatkan memori telefon mudah alih: int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
2) Pasangan nilai kunci dalam LruCache ialah URL dan imej yang sepadan
3) Tulis semula kaedah yang dipanggil sizeOf, yang mengembalikan bilangan gambar.
private LruCache mMemoryCache; private LruCacheUtils() { if (mMemoryCache == null) mMemoryCache = new LruCache( MAXMEMONRY / 8) { @Override protected int sizeOf(String key, Bitmap bitmap) { // 重写此方法来衡量每张图片的大小,默认返回图片数量。 return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { Log.v("tag", "hard cache is full , push to soft cache"); } }; }
4) Kaedah berikut adalah untuk mengosongkan cache, menambah gambar pada cache, mendapatkan gambar daripada cache dan mengeluarkannya daripada cache.
Mengalih keluar dan mengosongkan cache adalah satu kemestian, kerana pengendalian cache imej yang tidak betul akan menyebabkan limpahan memori, jadi anda mesti memberi perhatian.
public void clearCache() { if (mMemoryCache != null) { if (mMemoryCache.size() > 0) { Log.d("CacheUtils", "mMemoryCache.size() " + mMemoryCache.size()); mMemoryCache.evictAll(); Log.d("CacheUtils", "mMemoryCache.size()" + mMemoryCache.size()); } mMemoryCache = null; } } public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (mMemoryCache.get(key) == null) { if (key != null && bitmap != null) mMemoryCache.put(key, bitmap); } else Log.w(TAG, "the res is aready exits"); } public synchronized Bitmap getBitmapFromMemCache(String key) { Bitmap bm = mMemoryCache.get(key); if (key != null) { return bm; } return null; } /** * 移除缓存 * * @param key */ public synchronized void removeImageCache(String key) { if (key != null) { if (mMemoryCache != null) { Bitmap bm = mMemoryCache.remove(key); if (bm != null) bm.recycle(); } } }
Kandungan di atas dipetik daripada - teknologi caching memori LruCache untuk caching imej, rujukan lembut
Ringkasan bahagian ini:
Bahagian ini menerangkan ia kepada semua Punca masalah OOM juga diringkaskan di Internet untuk mengelakkan OOM disebabkan oleh Bitmap. Beberapa penyelesaian, kerana aplikasi yang dibuat oleh syarikat semuanya berasaskan peta dan jarang melibatkan gambar, jadi penulis tidak menghadapi masalah OOM. Jadi saya tidak begitu biasa dengan ini~ Dalam kursus lanjutan pengurusan ingatan berikut, kita akan perlahan-lahan bergelut dengan masalah OOM ini. Itu sahaja untuk bahagian ini, terima kasih~
Rujukan: Analisis dan Penyelesaian Masalah OOM dalam Aplikasi Android