在编程的过程中通过一些细节上的把握,减少应用的内存占用,同时要保证应用在长时间的运行下内存的占用不会有太大变化,尽可能的保证应用的内存占用稳定,这里就不罗列出现内存你泄漏的情况了,主要是罗列在正常编程的情况下保证应用程序尽可能的低的内存占用。
1.避免不必要的内存调用和对象的创建
不必要的对象创建不仅会提高应用的内存占用,同时还会更加频繁的造成虚拟机的GC,频繁的GC也会对性能造成影响。
2.使用更加有效的数据结构
Android在Java的基础上提供了Sparse*Array类来更有效的管理数据,另外看如下代码:
Map<Integer,String> map = new HashMap<Integer,String>();
上述代码中,使用int来代替Integer会更好,因为这样可以避免对象的创建,当然一些特殊的情况下还是要使用Integer的,不过在绝大多数的场景中都可以使用int来代替。
Android提供的数据结构更有效地将值映射到其他对象。如果可能使用这些对象,它们会避免对象创建,就像使用HashMap一样。对象创建可能很昂贵,应该避免减少垃圾收集器运行所需的次数。
- SparseArray<E> key为Integer对象的Map,可以省去Integer对象的创建。
- SparseBooleanArray key为Integer,值为Boolean的Map
- SparseIntArray key和值都为int的Map
调用示例:
SparseArray<String> map = new SparseArray<String>();
map.put(1, "Hello");
3.图像处理
位图可以分配大量的内存,如果加载的完全大小。建议将所需大小的位图加载到内存中。假设有一个在100x100 dp中显示图像的应用程序,应该在这个大小中加载图像。
// instruct BitmapFactory to only the bounds and type of the image
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
// get width and height
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
// type of the image
String imageType = options.outMimeType;
之后,可以加载图像的缩放版本。Android在缩放图像方面非常出色。可以使用以下方法(从官方的Android文档中)来计算基于2的比例因子。
public static Bitmap decodeBitmapWithGiveSizeFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
此方法可用于将图像分配给视图,如下面的示例所示。
viewWidth = imageView.getWidth();
viewHeight = imageView.getHeight();
imageView.
imageView.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.id.myimage, viewWidth, viewHeight));
4.循环优化
- 尽量不要在循环中创建很多的临时变量
- 可以将大型的循环拆散、分段或者按需执行
5.dex优化
dex的优化其实是对编程时的类的放置顺序的调整,将相互调用频繁或者相同功能的类集中放在同一个包下,而不是按照类的类型来进行分包,如activity、view这些。
关于4和5优化点的补充说明
第四和第五点的优化其实都是针对内存碎片化的问题进行优化的。先说明下什么是内存碎片化,简单的来说,内存是由多个大小相同的物理页面组成的,通常每个物理页面的大小为4kb。当要加载的数据小于或者等于4kb的时候,数据需要使用一个物理页面来存储,当多个数据加载但大小小于4kb的时候,也是只需要一个物理页面。而内存碎片化就是一个页面不能被完整的利用导致的。假设现在有4个2kb的数据需要被加载,那么这4个数据就刚好占用了两个物理页面A和B,使用了一段时间后,A和B页面中都有2kb的数据被系统回收了,也就是说A和B页面都只剩下了2kb的数据,还可以再存放2kb,这就是内存碎片的问题。如果这个时候又有2kb的数据需要被加载,系统会选择A页面或者B页面进行插入,但如果这个时候需要加载的数据大于2kb,那么系统会选择重新分配一个物理页面,从而导致内存占用的提高。
本人第一次写博客,是转行写代码的。如果有理解错误的地方还请各位大神指正。