Article source: zwkufo.blog.163.com/blog/static…

Android often causes Out of Memory errors when loading large backgrounds or large numbers of images. Based on my experience with these problems and the experience of other developers, this article provides the following solutions (some of the code and text source cannot be verified) :

\

Scheme 1, when reading the picture, pay attention to the method call, appropriate compression

. Try not to use setImageBitmap setImageResource or BitmapFactory decodeResource to set up a large, because these functions in the completion of decode, This is done through createBitmap in the Java layer, which consumes more memory.

. As a result, to switch to pass BitmapFactory decodeStream method, create a bitmap, it set as ImageView source, The biggest secret of decodeStream is that it calls JNI>>nativeDecodeAsset() directly to decode, eliminating the need to use createBitmap in the Java layer, thus saving space in the Java layer.

        InputStream is = this.getResources().openRawResource(R.drawable.pic1);

        BitmapFactory.Options options = new BitmapFactory.Options();

        options.inJustDecodeBounds = false;

options.inSampleSize = 10; // width, hight set to 1/10

        Bitmap btp = BitmapFactory.decodeStream(is, null, options);

\

If the image is read with the Config parameter, it can effectively reduce the Memory load, and thus effectively prevent out of Memory exceptions.

/ * *

* Read images from local resources in the most memory efficient way

     *  @param context

     *  @param resId

     *  @return

* /

    public 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;

// Get the resource image

        InputStream is = context.getResources().openRawResource(resId);

        return BitmapFactory.decodeStream(is, null, opt);

        }

\

In addition, decodeStream directly take pictures to read bytecode, not according to the machine’s various resolutions to automatically adapt, after the use of decodeStream, the need to configure the corresponding picture resources in HDPI and MDPI, LDPI, otherwise in different resolutions on the machine are the same size (pixel number), It shows the wrong size.

\

Scheme two, in the appropriate time to recover the memory occupied by the picture

Normally an Activity or Fragment can release image resources with onStop/onDestroy:

if(imageView ! = null && imageView.getDrawable() ! = null){

      Bitmap oldBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();    

      imageView.setImageDrawable(null);    

if(oldBitmap ! = null){

            oldBitmap.recycle();    

            oldBitmap = null;   

      }    

 }   

 // Other code.

 System.gc();

\

When releasing resources, you need to pay attention to whether the freed Bitmap or associated Drawable is referenced by other classes. If it is used normally, you can use the bitmap.isrecycled () method to check whether or not it is marked for recycling. If it is used by UI thread interface related code, you need to be careful not to reclaim resources that might be used, or else you might throw a system exception:

E/AndroidRuntime: java.lang.IllegalArgumentException: Cannot draw recycled bitmaps

And the exception cannot be effectively caught and handled.

\

Plan 3. Avoid complete loading of images when unnecessary

Only need to know the image size of the case can be incomplete to load the image into memory.

Bitmapfactory.options to set inJustDecodeBounds to true and use decodeFile() to calculate the size of an image without allocating space. Example:

 BitmapFactory.Options opts = new BitmapFactory.Options();    

// Set inJustDecodeBounds to true

 opts.inJustDecodeBounds = true;    

// Use decodeFile to get the width and height of the image

 BitmapFactory.decodeFile(path, opts);    

// Print out the width and height of the image

 Log.d(“example”, opts.outWidth + “,” + opts.outHeight);

(PS: The principle is to read the basic information of the picture through the header information of the picture)

\

Scheme 4. Optimize the heap memory allocation of Dalvik VM

The HEAP is the part of the VM that takes up the most memory and is usually allocated dynamically. The size of the heap is not fixed, and there is usually an allocation mechanism to control its size. For example, the initial HEAP is 4M, and when 4M space is occupied more than 75%, the reallocation HEAP is 8M. When 8M is occupied more than 75%, the allocated heap is 16M large. On the other hand, when the 16M heap is less than 30% utilized, reduce its size to 8M large. Resizing the heap, especially compression, generally involves copying memory, so changing the size of the heap has a negative impact on efficiency.

Heap Utilization is the Utilization of the Heap. When the actual utilization deviates from this percentage, the virtual machine adjusts the heap memory size during GC to bring the actual utilization closer to this percentage. Using the setTargetHeapUtilization method provided by the Dalvik.system. VMRuntime class can increase the processing efficiency of the program heap memory.

Private final static float TARGET_HEAP_UTILIZATION = 0.75f;

// can be called when the program onCreate

 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

* * * *

Plan 5: Customize the Heap size

For some Android projects, the performance bottleneck is mainly caused by Android’s own memory management mechanism. At present, mobile phone manufacturers are stingy with RAM, and RAM is very sensitive to the performance of software fluency. In addition to optimizing Dalvik VM heap memory allocation, We can also force to define the memory size of our software. We use the dalvik.system.VMRuntime class provided by Dalvik to set the minimum heap memory for example:

private final static int CWJ_HEAP_SIZE = 6 * 1024 * 1024 ;

VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); // Set the minimum heap memory size to 6MB.

\

The setMinimumHeapSize function only changes the lower limit of the Heap. It prevents too many Heap allocations. When the minimum HeapSize is set above the Max HeapSize, it still uses the upper limit of the Heap.

\

Finally, we introduce the memory algorithm of the image occupying process. The basic class for processing images in Android is Bitmap, which, as the name suggests, is a Bitmap. Memory usage algorithm such as: image width*height*Config.

If Config is set to ARGB_8888, the above Config is 4. A 480*320 image takes up 480*320*4 bytes of memory.

By default, the memory usage of android processes is 16M, because Bitmap in addition to Java holds data, the underlying C++ skia graphics library also holds a SKBitmap object, so the recommended size of images should not exceed 8M. This can be adjusted and the parameters can be set when the source code is compiled.

\