8.2.2 Bitmap-Induced OOM Issues
Category Android Basic Tutorial
Introduction:
>
In the previous section, we learned the basic usage of Bitmap, and in this section, we will explore the OOM issues related to Bitmap. You may have encountered, or not encountered, OOM issues due to Bitmap in actual development. In this section, we will focus on this topic to learn what OOM is, why it occurs, and how to improve OOM issues caused by Bitmap.
1. What is OOM? Why does it occur?
Answer: Out Of Memory (OOM), as we know, Android systems allocate a separate workspace or a separate Dalvik virtual machine for each app, so each app can run independently without affecting each other! Android has a maximum memory limit for each Dalvik virtual machine. If the current memory usage plus the memory resources we apply for exceeds this limit, the system will throw an OOM error! Also, don't confuse this with RAM. Even if there is more than 1GB of free memory in the current RAM, OOM can still occur! Don't mix up RAM (physical memory) with OOM! If RAM is insufficient, it's about killing applications, not just OOM! The maximum memory standard in Dalvik varies by model and can be obtained by calling:
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
Log.e("HEHE","Maximum Memory: " + activityManager.getMemoryClass());
Or directly enter in the command line:
adb shell getprop | grep dalvik.vm.heapgrowthlimit
You can also open the system source code /system/build.prop file and look at the information in this part of the file:
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
We focus on three aspects: heapstartsize, the initial size of the heap memory; heapgrowthlimit, the maximum heap memory size for standard applications; and heapsize, which sets the maximum heap memory size for applications using android:largeHeap.
I tested the normal maximum memory allocation standard on a few models I have:
You can also try the models you have.
Okay, enough about the generation of OOM issues, let's move on to some tips for avoiding OOM caused by Bitmap!
2. Summary of Techniques to Avoid OOM Caused by Bitmap
1) Use low memory-consuming encoding methods
In the previous section, we mentioned BitmapFactory.Options. We can set the inPreferredConfig property, which defaults to Bitmap.Config.ARGB_8888**, and we can change it to **Bitmap.Config.ARGB_4444.
2) Image compression
Again, using BitmapFactory.Options, we can set the inSampleSize to adjust the scaling factor. For example, setting it to 2 reduces the width and height to 1/2 of the original, making the image 1/4 of the original size. If no scaling is needed, set it to 1. However, don't compress blindly, as a too small value can result in blurry images and distortion. Therefore, we need to dynamically calculate an appropriate value for inSampleSize in the program. The Options class also has a method: inJustDecodeBounds. Setting this parameter to true allows us to calculate the original image's width and height without allocating memory space. We can then use options.outWidth and options.outHeight to get the image's width and height and calculate an appropriate inSampleSize. Thanks to Jie Shen for providing the code—extracted from Hongyang's blog!
public static int calculateInSampleSize(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;
}
Then use the above method:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // Remember to set this property to false
Bitmap bitmap = null;
bitmap = BitmapFactory.decodeFile(url, options);
options.inSampleSize = computeSampleSize(options,128,128);
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
/* The following two fields need to be used together */
options.inPurgeable = true;
options.inInputShareable = true;
options.inJustDecodeBounds = false;
try {
bitmap = BitmapFactory.decodeFile(url, options);
} catch (OutOfMemoryError e) {
Log.e(TAG, "OutOfMemoryError");
}
3. Timely Recycling of Images
If you reference a large number of Bitmap objects and the application does not need to display all images simultaneously, you can recycle Bitmap objects that are temporarily not in use. For some scenarios where the usage of images is clear, you can actively recycle them, such as guide page images, which can be recycled after use, or frame animations, where one is loaded, drawn, and released at a time! Load when needed, and set to null or recycle when not displayed. For example: imageView.setImageResource(0); However, in some cases, specific images may be repeatedly loaded, released, and reloaded, which is inefficient.
4. Other Methods
The following methods have not been used by me, and you can refer to relevant materials:
1. Simple management of image resources through SoftReference
Create a hashmap of SoftReference. When using an image, first query whether the hashmap has a softreference, and whether the image in the softreference is empty. If it is empty, load the image into the softreference and add it to the hashmap. There is no need to handle the recycling and release of images explicitly in the code, as the gc will automatically release resources. This method is simple and practical, and can一定程度上 avoid前一种方法反复加载释放的低效率。但还不够优化。
Example code:
private Map<String, SoftReference<Bitmap>> imageMap
= new HashMap<String, SoftReference<Bitmap>>();
public Bitmap loadBitmap(final String imageUrl,final ImageCallBack imageCallBack) {
SoftReference<Bitmap> 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) {
//Add to cache
Bitmap bitmap = (Bitmap)msg.obj;
imageMap.put(imageUrl, new SoftReference<Bitmap>(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 ;
}
//Download image from the internet
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 + sd cache method
>
Starting from Android 3.1, the official also provides LruCache for cache processing. When the size of stored images exceeds the value set by LruCache, the least recently used images will be recycled, and the system will automatically release memory!
Usage example:
Steps:
1) First, set the memory size for caching images. Here, I set it to 1/8 of the phone's memory. The method to get the phone's memory: int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
2) The key-value pairs in LruCache are URL and corresponding image.
3) Override the sizeOf method to return the number of images.
private LruCache<String, Bitmap> mMemoryCache;
private LruCacheUtils() {
if (mMemoryCache == null)
mMemoryCache = new LruCache<String, Bitmap>(
MAXMEMONRY / 8) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// Override this method to measure the size of each image, default returns the number of images.
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) The following methods are for clearing the cache, adding images to the cache, retrieving images from the cache, and removing images from the cache.
Removing and clearing the cache are essential tasks because improper handling of image caching can lead to out-of-memory errors, so it must be taken seriously.
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 already exists");
}
public synchronized Bitmap getBitmapFromMemCache(String key) {
Bitmap bm = mMemoryCache.get(key);
if (key != null) {
return bm;
}
return null;
}
/**
* Remove cache
*
* @param key
*/
public synchronized void removeImageCache(String key) {
if (key != null) {
if (mMemoryCache != null) {
Bitmap bm = mMemoryCache.remove(key);
if (bm != null)
bm.recycle();
}
}
}
The above content is excerpted from——Image Caching Techniques: LruCache, Soft References
Summary:
>
This section explains the causes of OOM issues and summarizes some solutions provided online to avoid OOM caused by Bitmap. Since the company's APP is mostly map-based and rarely involves images, the author has not encountered OOM issues and is not very familiar with them. We will delve into the OOM issue in the advanced course on memory management. That's all for this section, thank you.
References: Analysis and Solutions for OOM Issues in Android Applications
-1.0 Android Basic Introduction Tutorial
-1.0.1 2015 Latest Android Basic Introduction Tutorial Table of Contents
-1.1 Background and System Architecture Analysis
-1.2 Development Environment Setup
-1.2.1 Developing Android APP with Eclipse + ADT + SDK
-1.2.2 Developing Android APP with Android Studio
-1.3 Solving SDK Update Issues
-1.4 Genymotion Emulator Installation
-1.5.1 Git Tutorial for Basic Local Repository Operations
-1.5.2 Git: Setting Up a Remote Repository on GitHub
-1.6 How to Use the 9-Patch Image
-1.7 Interface Prototype Design
-1.8 Project Source Analysis (Various Files, Resource Access)
-1.9 Android Application Signing and Packaging
-1.11 Decompiling APK to Obtain Code & Resources
-2.1 Concepts of View and ViewGroup
-2.2.1 LinearLayout (Linear Layout)
-2.2.2 RelativeLayout (Relative Layout)
-2.2.3 TableLayout (Table Layout)
-2.2.4 FrameLayout (Frame Layout)
-2.2.5 GridLayout (Grid Layout)
-2.2.6 AbsoluteLayout (Absolute Layout)
-2.3.1 Detailed Explanation of TextView (Text Box)
-2.3.2 Detailed Explanation of EditText (Input Box)
-2.3.3 Button and ImageButton (Image Button)
-2.3.5.RadioButton (Radio Button) & Checkbox (Checkbox)
-2.3.6 ToggleButton and Switch (Switch Button)
-2.3.7 ProgressBar (Progress Bar)
-2.3.9 RatingBar (Star Rating Bar)
-2.4.1 ScrollView (Scroll Bar)
-2.4.2 Date & Time Components (Part 1)
-2.4.3 Date & Time Components (Part 2)
-2.4.5 Simple Usage of ListView
-2.4.6 Optimization of BaseAdapter
-2.4.7 Focus Issues with ListView
-2.4.8 Solving Checkbox Misalignment in ListView
-2.4.9 Data Update Issues in ListView
-2.5.0 Building a Reusable Custom BaseAdapter
-2.5.1 Implementing Multi-Layout ListView Items
-2.5.2 Basic Usage of GridView (Grid View)
-2.5.3 Basic Usage of Spinner (List Option Box)
-2.5.4 Basic Usage of AutoCompleteTextView (Auto-Complete Text Box)
-2.5.5 Basic Usage of ExpandableListView (Collapsible List) ```
- 2.5.6 Basic Usage of ViewFlipper (Flip View)
- 2.5.7 Basic Usage of Toast (Toast)
- 2.5.8 Detailed Explanation of Notification (Status Bar Notification)
- 2.5.9 Detailed Explanation of AlertDialog (Dialog Box)
- 2.6.0 Basic Usage of Other Common Dialogs
- 2.6.1 Basic Usage of PopupWindow (Floating Box)
- 2.6.2 Menu (Menu)
- 2.6.3 Simple Usage of ViewPager
- 2.6.4 Simple Usage of DrawerLayout (Official Side Sliding Menu)
- 3.1.1 Event Handling Mechanism Based on Listeners
- 3.2 Event Handling Mechanism Based on Callbacks
- 3.3 Analysis of Handler Message Passing Mechanism
- 3.4 TouchListener vs OnTouchEvent + Multi-touch
- 3.5 Listening for Content Changes in EditText
- 3.6 Responding to System Setting Events (Configuration Class)
- 3.7 AsyncTask Asynchronous Task
- 3.8 Gestures (Gestures)
- 4.1.1 Introduction to Activity
- 4.1.2 Getting Started with Activity
- 4.1.3 Advanced Activity
- 4.2.1 Introduction to Service
- 4.2.2 Advanced Service
- 4.2.3 Mastering Service
- 4.3.1 Introduction to BroadcastReceiver
- 4.3.2 In-depth BroadcastReceiver
- 4.4.1 Introduction to ContentProvider
- 4.4.2 Further Exploration of ContentProvider - Document Provider
- 4.5.1 Basic Usage of Intent
- 4.5.2 Passing Complex Data with Intent
- 5.1 Basic Overview of Fragment
- 5.2.1 Fragment Example Analysis - Bottom Navigation Bar Implementation (Method 1)
- 5.2.2 Fragment Example Analysis - Bottom Navigation Bar Implementation (Method 2)
- 5.2.3 Fragment Example Analysis - Bottom Navigation Bar Implementation (Method 3)
- 5.2.4 Fragment Example Analysis - Bottom Navigation Bar + ViewPager Swipe to Switch Pages
- 5.2.5 Fragment Example Analysis - Simple Implementation of News (Shopping) App List Fragment
- 6.1 Data Storage and Access - File Storage and Reading
- 6.2 Data Storage and Access - SharedPreferences for Saving User Preferences
- 6.3.1 Data Storage and Access - Introduction to SQLite Database
- 6.3.2 Data Storage and Access - Further Exploration of SQLite Database
- 7.1.1 Android Network Programming - Learning Objectives and HTTP Protocol
- 7.1.2 Android HTTP Request Headers and Response Headers
- 7.1.3 Android HTTP Request Method: HttpURLConnection
- 7.1.4 Android HTTP Request Method: HttpClient
- 7.2.1 Android XML Data Parsing
- 7.2.2 Android JSON Data Parsing
- 7.3.1 Android File Upload
- 7.3.2 Android File Download (1)
- 7.3.3 Android File Download (2)
- 7.4 Android Calling WebService
- 7.5.1 Basic Usage of WebView (Web View)
- 7.5.2 WebView and JavaScript Interaction Basics
- 7.5.3 Notes on WebView After Android 4.4
- 7.5.4 WebView File Download
- 7.5.5 WebView Cache Issues
- 7.5.6 WebView Handling Webpage Error Codes
- 7.6.1 Socket Learning Network Basics Preparation
- 7.6.2 TCP Protocol Based Socket Communication (1)
- 7.6.3 TCP Protocol Based Socket Communication (2)
- 7.6.4 UDP Protocol Based Socket Communication
- 8.1.1 Summary of 13 Drawable Types in Android Part 1
- 8.1.2 Summary of 13 Drawable Types in Android Part 2
- 8.1.3 Summary of 13 Drawable Types in Android Part 3
- 8.2.1 Comprehensive Analysis of Bitmap (Bitmap) Part 1
- 8.2.2 OOM Issues Caused by Bitmap
- 8.3.1 Detailed Explanation of Three Drawing Tools
- 8.3.2 Drawing Class Practical Examples
- 8.3.3 Paint API - MaskFilter (Mask)
- 8.3.4 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 1)
- 8.3.5 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 2)
- 8.3.6 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 3)
- 8.3.7 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 4)
- 8.3.8 Paint API - Xfermode and PorterDuff Detailed Explanation (Part 5)
- 8.3.9 Paint API - ColorFilter (Color Filter) (1/3)
- 8.3.10 Paint API - ColorFilter (Color Filter) (2/3)
- 8.3.11 Paint API - ColorFilter (Color Filter) (3/3)
- 8.3.12 Paint API - PathEffect (Path Effect)
- 8.3.13 Paint API - Shader (Image Rendering)
- 8.3.14 Paint Enumerations/Constants and ShadowLayer Shadow Effect
- 8.3.15 Paint API - Typeface (Font Style)
- 8.3.16 Canvas API Detailed Explanation (Part 1)
- 8.3.17 Canvas API Detailed Explanation (Part 2) Clipping Methods
- 8.3.18 Canvas API Detailed Explanation (Part 3) Matrix and drawBitmapMesh
- 8.4.1 Android Animation Collection - Frame Animation
- 8.4.2 Android Animation Collection - Tween Animation
- 8.4.3 Android Animation Collection - Property Animation - Introduction
- 8.4.4 Android Animation Collection - Property Animation - Further Insights
- 9.1 Using SoundPool to Play Sound Effects (Duang~)
- 9.2 MediaPlayer for Audio and Video Playback
- 9.3 Using Camera to Take Photos
- 9.4 Using MediaRecord to Record Audio
- 10.1 TelephonyManager (Phone Manager)
- 10.2 SmsManager (SMS Manager)
- 10.3 AudioManager (Audio Manager)
- 10.4 Vibrator (Vibrator)
- 10.5 AlarmManager (Alarm Service)
- 10.6 PowerManager (Power Service)
- 10.7 WindowManager (Window Management Service)
- 10.8 LayoutInflater (Layout Service)
- 10.9 WallpaperManager (Wallpaper Manager)
- 10.10 Sensor Topics (1) - Introduction
- 10.11 Sensor Topics (2) - Orientation Sensor
- 10.12 Sensor Topics (3) - Accelerometer/Gyroscope Sensor
- 10.12 Sensor Topics (4) - Understanding Other Sensors
- 10.14 Android GPS Introduction
- 11.0《2015 Latest Android Basic Beginner's Tutorial》Completion Celebration~
- 12.1 Android Practice: DrySister Viewing Girls App (Version 1) - Project Setup and Simple Implementation
- 12.2 DrySister Viewing Girls App (Version 1) - 2. Parsing Backend Data
- 12.3 DrySister Viewing Girls App (Version 1) - 3. Image Loading Optimization (Writing an Image Caching Framework)
- 12.4 DrySister Viewing Girls App (Version 1) - 4. Adding Data Caching (Introducing SQLite)
- 12.5 DrySister Viewing Girls App (Version 1) - 5. Code Review, Adjustment, and Logging Class Writing
- 12.6 DrySister Viewing Girls App (Version 1) - 6. Icon Creation, Obfuscation, Signing, APK Slimming, App Release