This example summarizes the memory overflow solution (OOM) for Android programming. Share it for your reference, as follows:
In the recent project, I found that there are too many pictures loaded or too large, and I often have OOM problems. I also provide many methods to find online information, but I feel a little confused. I have tested them today on three Android phones of different models. Because they have effects and results, Xiaoma will give a detailed summary today for friends to communicate and learn, and for me to improve in solving OOM problems in the future. Let me talk about it in advance. The film is a bit long and there are too many things involved. Everyone will look at it patiently and will definitely gain something. Many of the things in it are also used by Xiaoma to learn to refer to online materials. Let’s talk about it briefly:
Generally, the common methods we use when encountering memory problems also have relevant information online, roughly the following:
1: Do some processing on memory references. Commonly used ones include soft references, reinforced references, and weak references.
2: When loading pictures in memory, it is directly processed in memory, such as: boundary compression
Three: Dynamic memory recycling
Fourth: Optimize the heap memory allocation of Dalvik virtual machines
Five: Custom heap memory size
But is it really that simple? Just use the above method to solve OOM? No, keep watching...
The following Xiaoma will sort out several solutions in the order above, and the number number corresponds to the above:
1: SoftReference, PhantomRefrence, WeakReference, these three classes are applications of java objects in heap. Through these three classes, you can interact with GC simply. In addition to these three, there is another one that is the most commonly used strong reference.
1.1: Strong reference, such as the following code:
Object o=new Object(); Object o1=o;
The first sentence in the above code is to create a new Object object in the heap heap to refer to this object through o, and the second sentence is to create a reference to the object in the heap heap through o1 and new Object(). Both references are strong references. As long as there is a reference to the object in the heap, gc will not collect the object. If the following code is passed:
o=null; o1=null
Objects in heap include strong accessibility objects, soft accessibility objects, weak accessibility objects, virtual accessibility objects and unreachable objects. The order of application is strong, soft, weak, and virtual. The object belongs to which it belongs is determined by its strongest reference. as follows:
String abc=new String("abc"); //1 SoftReference<String> abcSoftRef=new SoftReference<String>(abc); //2 WeakReference<String> abcWeakRef = new WeakReference<String>(abc); //3 abc=null; //4 ();//5
In the above code:
The first line creates an object with content "abc" in the heap pair and creates a strong reference to the object, which is strongly accessible. The second and third lines establish soft and weak references to objects in the heap respectively. At this time, the objects in the heap are still strong and accessible. After the fourth line, the object in the heap is no longer strong and soft. Also, the fifth line becomes weak and accessible after execution.
1.2: Soft Quotation
Soft references are mainly used for memory-sensitive caches. All soft references will be cleared before jvm reports insufficient memory, so that gc can collect soft-accessible objects, which may solve the problem of tight memory and avoid memory overflow. When will be collected depends on the algorithm of gc and the size of available memory when gc runs. When gc decides to collect soft references, the following process is performed, the above abcSoftRef is an example:
1 First set the reference of abcSoftRef to null, and no longer refer to the new String("abc") object in heap.
2 Set the new String("abc") object in the heap to finalizable.
3 When the finalize() method of the new String("abc") object in heap is run and the memory occupied by the object is released, abcSoftRef is added to its ReferenceQueue.
Note: ReferenceQueue soft references and weak references can be dispensable, but virtual references must be present, see:
Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)
Objects pointed to by Soft Reference will not be cleared even if there is no Direct Reference. SoftReference is used to design object-cache. In this way, SoftReference can not only cache the object, but also will not cause insufficient memory errors (OutOfMemoryError). I think Soft Reference is also suitable for pooling techniques.
A obj = new A(); Refenrence sr = new SoftReference(obj); //When quotedif(sr!=null){ obj = (); }else{ obj = new A(); sr = new SoftReference(obj); }
1.3: Weak Quotation
When gc encounters a weakly accessible object, releases a reference to abcWeakRef to collect the object. But gc may need to use this to find the weakly accessible object. It can be clearly seen through the following code:
String abc=new String("abc"); WeakReference<String> abcWeakRef = new WeakReference<String>(abc); abc=null; ("before gc: "+()); (); ("after gc: "+());
Running results:
before gc: abc
after gc: null
The execution process of gc collecting weakly accessible objects is the same as soft-accessible, except that gc will not decide whether to collect the object based on the memory situation. If you want to obtain information about an object at any time but do not want to affect the garbage collection of this object, then you should use Weak Reference to remember this object instead of using a general reference.
A obj = new A(); WeakReference wr = new WeakReference(obj); obj = null; //Wait for a while, the obj object will be garbage collected... if (()==null) { ("obj has been cleared"); } else { ("obj has not been cleared yet, its message is "+()); } ... }
In this example, the object pointed to by this Reference can be obtained through get(). If the return value is null, it means that the object has been cleared. This kind of trick is often used when designing programs such as Optimizer or Debugger because such programs require information from a certain object, but cannot affect the garbage collection of this object.
1.4: Virtual Quotation
It means nothing. After establishing a virtual reference, the result is always null through the get method. Through the source code, you will find that the virtual reference leads to writing the referenced object into the reference, but the get method returns the result as null. Let's first look at the process of interacting with gc and talk about its function.
1.4.1 Do not set the reference to null, directly set the new String("abc") object in the heap to finalizable.
1.4.2 Unlike soft references and weak references, first add the PhantomRefrence object to its ReferenceQueue. Then release the virtually accessible object.
You will find that before collecting the new String("abc") object in the heap, you can do something else. You can understand its function through the following code.
import ; import ; import ; import ; public class Test { public static boolean isRun = true; public static void main(String[] args) throws Exception { String abc = new String("abc"); (() + "@" + ()); final ReferenceQueue referenceQueue = new ReferenceQueue<String>(); new Thread() { public void run() { while (isRun) { Object o = (); if (o != null) { try { Field rereferent = .getDeclaredField("referent"); (true); Object result = (o); ("gc will collect:" + () + "@" + ()); } catch (Exception e) { (); } } } } }.start(); PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc, referenceQueue); abc = null; ().sleep(3000); (); ().sleep(3000); isRun = false; } }
The result is
class @96354
gc will collect:class @96354
Okay, that's all about the quotes, let's see 2
2: The test was performed for compressing the pony in memory. This method is feasible for a small number of not-so-large pictures, but too many and large pictures. A stupid way is to compress it in memory first, and then use soft references to avoid OOM. The two methods are as follows, please refer to it:
The code of method one is as follows:
@SuppressWarnings("unused") private Bitmap copressImage(String imgPath){ File picture = new File(imgPath); Options bitmapFactoryOptions = new (); //The following setting is to change the picture boundary into adjustable = true; = 2; int outWidth = ; int outHeight = ; bmap = ((), bitmapFactoryOptions); float imagew = 150; float imageh = 150; int yRatio = (int) ( / imageh); int xRatio = (int) Math .ceil( / imagew); if (yRatio > 1 || xRatio > 1) { if (yRatio > xRatio) { = yRatio; } else { = xRatio; } } = false; bmap = ((), bitmapFactoryOptions); if(bmap != null){ //(bmap); return bmap; } return null; }
The second code of the method is as follows:
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; /** * @Title: * @Description: Photo preview control class * @author XiaoMa */ public class PhotoScanActivity extends Activity { private Gallery gallery ; private List<String> ImageList; private List<String> it ; private ImageAdapter adapter ; private String path ; private String shopType; private HashMap<String, SoftReference<Bitmap>> imageCache = null; private Bitmap bitmap = null; private SoftReference<Bitmap> srf = null; @Override public void onCreate(Bundle savedInstanceState) { (savedInstanceState); getWindow().setFlags(.FLAG_FULLSCREEN, .FLAG_FULLSCREEN); setContentView(); Intent intent = (); if(intent != null){ if(("bundle") != null){ Bundle bundle = ("bundle"); path = ("path"); shopType = ("shopType"); } } init(); } private void init(){ imageCache = new HashMap<String, SoftReference<Bitmap>>(); gallery = (Gallery)findViewById(); ImageList = getSD(); if(() == 0){ (getApplicationContext(), "No photo, please go back to take a photo and use the preview", Toast.LENGTH_SHORT).show(); return ; } adapter = new ImageAdapter(this, ImageList); (adapter); (longlistener); } /** * Gallery long press event operation is implemented */ private OnItemLongClickListener longlistener = new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) { //Add to delete photos here to add a long press event dialog = new (); (); ("Delete prompt"); ("Are you sure you want to delete this photo?"); ("Sure", new () { @Override public void onClick(DialogInterface dialog, int which) { File file = new File((position)); boolean isSuccess; if(()){ isSuccess = (); if(isSuccess){ (position); (); //(adapter); if(() == 0){ (getApplicationContext(), getResources().getString(), Toast.LENGTH_SHORT).show(); } (getApplicationContext(), getResources().getString(), Toast.LENGTH_SHORT).show(); } } } }); ("Cancel",new () { @Override public void onClick(DialogInterface dialog, int which) { (); } }); ().show(); return false; } }; /** * Get all picture files on the SD card * @return */ private List<String> getSD() { /* Set the current path */ File fileK ; it = new ArrayList<String>(); if("newadd".equals(shopType)){ //If you come in from viewing the new list item or merchant list item fileK = new File(); }else{ //A purely new fileK = new File(path); } File[] files = (); if(files != null && >0){ for(File f : files ){ if(getImageFile(())){ (()); Options bitmapFactoryOptions = new (); //The following setting is to change the picture boundary into adjustable = true; = 5; int outWidth = ; int outHeight = ; float imagew = 150; float imageh = 150; int yRatio = (int) ( / imageh); int xRatio = (int) Math .ceil( / imagew); if (yRatio > 1 || xRatio > 1) { if (yRatio > xRatio) { = yRatio; } else { = xRatio; } } = false; bitmap = ((), bitmapFactoryOptions); //bitmap = (()); srf = new SoftReference<Bitmap>(bitmap); ((), srf); } } } return it; } /** * Specific implementation of the method of obtaining image files * @param fName * @return */ private boolean getImageFile(String fName) { boolean re; /* Get the extension */ String end = fName .substring((".") + 1, ()) .toLowerCase(); /* Determine MimeType by the type of extension */ if (("jpg") || ("gif") || ("png") || ("jpeg") || ("bmp")) { re = true; } else { re = false; } return re; } public class ImageAdapter extends BaseAdapter{ /* Declare variable */ int mGalleryItemBackground; private Context mContext; private List<String> lis; /* ImageAdapter constructor */ public ImageAdapter(Context c, List<String> li) { mContext = c; lis = li; TypedArray a = obtainStyledAttributes(); mGalleryItemBackground = (.Gallery_android_galleryItemBackground, 0); (); } /* How many methods to rewrite getCount, and the number of pictures are sent back */ public int getCount() { return (); } /* The method you must rewrite getItem and pass it back to position */ public Object getItem(int position) { return (position); } /* The method that must be rewritten getItemId, pass and position */ public long getItemId(int position) { return position; } /* How many methods to rewrite getView, pass and several View objects */ public View getView(int position, View convertView, ViewGroup parent) { ("lis:"+lis); File file = new File((position)); SoftReference<Bitmap> srf = (()); Bitmap bit = (); ImageView i = new ImageView(mContext); (bit); (.FIT_XY); ( new (.WRAP_CONTENT, .WRAP_CONTENT)); return i; } } }
The first is to use boundary compression directly, and the second is to use soft references indirectly to avoid OOM when using boundary compression. However, everyone knows that after completing decode, these functions are eventually completed through the createBitmap of the java layer, which requires more memory consumption. If there are many pictures and large, this method will still refer to OOM exceptions. Don't worry, some methods can be solved. Keep reading. The following methods are also very useful:
1.
InputStream is = ().openRawResource(.pic1); options=new (); = false; = 10; //width, high is set to the original ten-oneBitmap btp =(is,null,options);
2.
if(!() ){ () //Recycle the memory occupied by the picture () //Remind the system to recover in time}
You can use the above code separately from the following code, which can also effectively alleviate memory problems... huh...
/** Don't mess with this place. To facilitate Xiaoma, I will put the two stickers together. Remember to use them separately when using them. * Read pictures of local resources in the most memory-saving way */ public static Bitmap readBitMap(Context context, int resId){ opt = new (); = .RGB_565; = true; = true; //Get resource pictures InputStream is = ().openRawResource(resId); return (is,null,opt); }
3: You can choose to use the following code dynamically in the appropriate place and explicitly call GC to recycle memory:
if(()==false) //If not recycled ();
4: This is fun. Optimizing the heap memory allocation of Dalvik virtual machine sounds very powerful. Let's see what's going on
For Android platform, the Dalvik JavaVM used in its hosting layer still has many places to optimize processing based on its current performance. For example, when developing some large games or resource-consuming applications, we may consider manually interfering with GC processing. Using the setTargetHeapUtilization method provided by the class can enhance the processing efficiency of program heap memory. Of course, we can refer to open source engineering for the specific principles. Here we will only talk about the usage method: The code is as follows:
You can call it when the program is onCreate
Just
5: Customize how much memory our application requires. This is a very violent one. Forced to set the minimum memory size, the code is as follows:
private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ; //Set the minimum heap memory to 6MB size().setMinimumHeapSize(CWJ_HEAP_SIZE);
Okay, the article is finished, and the film is a bit long because there are too many things involved. Xiaoma will post the source code for other articles. This article Xiaoma is directly tested with three Android real machines in the project. It is effective. The original code of the project will not be posted here. Otherwise, if the leak is done, it will be different. But here it will still be different due to the different mobile phones. Everyone has to choose the appropriate way to avoid OOM according to their needs. Come on, you will gain more or less every day. This is also a progress. Come on!
I hope this article will be helpful to everyone's Android programming design.