Android常见问题总结(1)

1 对象置null后发生的变化

我们先看一个常见的例子,代码如下:

public class Ball {
    public Ball(float x, float y, float r) {
        this.x = x;
        this.y = y;
        this.r = r;
    }
    public float x;
    public float y;
    public float r;
}

// main函数进行打印
ArrayList balls = new ArrayList<>();
Ball ball = new Ball(10, 20, 30);
balls.add(ball);
ball.x = 50;

for (Ball ball1 : balls) {
    Log.e(TAG, "x: " + ball1.x);
}

打印出来的log日志如下:

 x: 50.0

如果改成如下代码,是否有疑问,为什么balls里的对象还是有值,不为null。

ArrayList balls = new ArrayList<>();
Ball ball = new Ball(10, 20, 30);
balls.add(ball);
ball = null;

for (Ball ball1 : balls) {
    Log.e(TAG, "x: " + ball1.x);
}

打印出来的log日志如下:

 x: 10.0

我们来看看下面两张内存模型图,执行到balls.add(ball);这句代码时。

Android常见问题总结(1)_第1张图片
image.png

当执行到ball = null;这段代码时

Android常见问题总结(1)_第2张图片
image.png

我们的刻板印象里,引用更改后,会改变该引用对象的值,这个没错。但是当引用置空后,只是引用断开了与对象之间的连接,并不会把堆内存中的对象也置空。

2 内存泄漏

整体来说,内存泄漏,一般都是一个较短生命周期的对象,被一个较长生命周期的对象引用或持有,从而导致较短生命周期对象无法被GC回收。

1、比如该传递application对象的地方,传递了activity。
2、非静态内部类handler的使用。
3、一些资源的释放和回收,比如数据库,io流,bitmap等。
4、静态集合的不合理使用,比如没有进行回收和清理的逻辑,导致只增不减。

在非静态内部类handler的使用中,会引起一个话题,强,软,弱,虚引用问题。
软引用:内存不足时进行回收;
弱引用:GC触发时进行回收。
虚引用:GC触发时进行回收,为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知,可以作为对象回收的监听器。如果一个对象被虚引用持有着,那么当垃圾回收时,对象将被回收,但是虚引用会加入到一个引用队列中去,我们可以通过队列知道哪些对象被回收了。

在activity中使用非静态handler内部类,一般容易发生内存泄漏。针对这个问题,有两点优化。
第一,handler修改为静态;
第二,在activity的onDestroy方法中调用handler的removeCallbacksAndMessages方法。

经过实验,其实只做第二点优化也是可以的,但是还是有可能出现泄漏,因为gc时机不确定,如果removeCallbacksAndMessages调用立马gc,这时其实是有可能不能回收掉相应的activity。

所以修改为静态内部类,其生命周期与应用等同,引用的上下文为application,直接消除了这个顾虑。

3 Bitmap占多大内存

Bitmap占有多大内存和以下几个方面息息相关。

第一点,我们所选择的Options配置图片的颜色模式,比如Bitmap.Config.RGB_565Bitmap.Config.ARGB_8888,但这种方式不一定会生效。与加载的图片本身的颜色模式和加载的目标设备都有一定关系。
第二点,通过采样率inSampleSize配置,对图片进行缩放。
第三点,加载的图片如果存在于drawable文件夹中,那和放在哪个文件夹也有关。
第四点,和目标设备的dpi值有关。

各个文件夹与dpi值之间的关系。

mdpi hdpi xhdpi xxhdpi xxxhdpi
density 1 1.5 2 3 4
densityDpi 160 240 320 480 640

一张图片的所占用内存大小:

图片的argb属性值有关:
ARGB_8888,每个像素点4个字节(4byte)
RGB_565,每个像素点2个字节(2byte)

所显示设备的屏幕密度和所放的资源文件夹。如果设备屏幕密度为xxdpi,但是图片却放在drawable-xdpi中,那么图片会放大相应的倍数再显示到设备中。

打个比方,一张图片颜色模式为ARGB_8888,宽高100*200的图片,放在drawable-xhdpi文件夹中,显示在一个dpi为480的设备上,那么这个图片所占内存:
宽度:100*480\320 + 0.5 = 150.5
高度:200*480\320 + 0.5 = 300.5

字节大小数为 150.5 * 300.5 * 4 = 180901 byte

你可能感兴趣的:(Android常见问题总结(1))