Android面试题

Android面试(四)内存优化一

2017-07-30  本文已影响86人  小龙哥的开发日记

博客地址 :http://blog.csdn.net/w15321970103/article/details/76088905
内存优化

什么是OOM,OOM是如何造成的?

oom-out of memory(内存溢出), 当自身占用的内存加上要求分配的内存超过了系统给你的内存时, 系统就会抛出out of memory的异常(每个Android能用的内存是限的)比如: 当前应用只剩下4M的空间可用, 但你却加载得到一个需要占用5M空间的图片Bitmap对象, 就会抛出oom的异常


什么是内存泄漏,内存泄漏是如何造成的?

当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏


内存泄漏对程序的影响?

内存泄漏是造成应用程序OOM的主要原因之一!我们知道Android系统为每个应用程序分配的内存有限,
而当一个应用中产生的内存泄漏比较多时,这就难免会导致应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash


什么是内存抖动?

内存抖动可以看到内存的占用量短时间内大量被占用,短时间内又被大量释放,造成的原因变量短暂大量产生,又被大量释放,就会造成内存抖动,


什么是overDraw?

过度重绘:导致延迟绘制时间,做了很多无用功,消耗了内存

举例:在背景上加了背景颜色 在布局上又加了背景颜色
最后Button上又设置了颜色 那么重叠的部分就叫过度重绘


UI卡顿的原因?

一 首先我们要了解16ms黄金准则 : 一般来说,Android设备的屏幕刷新率为60帧每秒,要保持流畅就遇要每一帧不超过16.6MS每帧,如果超过就会发生跳帧的现象。

二 原因


如何内存优化?


布局优化

选用相对布局还是线性布局?

RelativeLayout : 在进行布局的时候会进行多次测量
嵌套越多测量次数越多

LinearLayout: 在设置权重的时候才会测量两次
相对布局可以让布局嵌套变少,而相对布局则测量少
所以最好的方式是结合使用


Merge和ViewStub的使用

<include>标签
include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,这在布局编写方便提供了大大的便利

<merge/>标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。<merge/>多用于替换FrameLayout或者当一个布局包含另一个时,<merge/>标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用<merge/>标签优化。

<ViewStub />标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用<ViewStub />标签,以减少内存使用量,加快渲染速度。<ViewStub />是一个不可见的,大小为0的View。<ViewStub />标签使用如下

<ViewStub
    android:layout="@layout/progress_overlay"  
    android:layout_width="fill_parent"  
    android:layout_height="wrap_content"  
    android:layout_gravity="bottom" />  

内存泄漏

android常见造成内存泄漏的问题是什么?

1 内存泄漏 是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,
从而造成的内存空间的浪费称为内存泄漏

2上下文导致的内存泄漏:举例 单例中持有的上下文是从activity传过来的,一旦activity不再需要,而被销毁的时候,因为单例的工具类还持有activity的引用,那么activity便不会被GC回收

3非静态内部类造成的内存泄漏 : 举例:(Handler造成的内存泄漏,AsyncTast内存泄漏等)当一个非静态内部类里做着一件耗时的任务,那么包含这个内部类的activity就算销毁也不回被回收。原因 非静态内部会持有外部类的引用(为什么会持有看下面)

4资源没有关闭造成的内存泄漏:如游标没有关闭 流没有关闭 bitmap没有释放等等


上下文导致内存泄漏的原因?

主要是GC原理,垃圾回收机制:Java采用根搜索算法,当GC Roots不可达时,并且对象finalize没有自救的情况下,才会回收。

回收对象:GC会收集那些不是GC roots且没有被GC roots引用的对象。


非静态内部类造成内存泄漏的原因?

1 静态内部类对外部类会存在一个隐式引用(因为非静态内部类可以调用外部类的方法,即然可以调用外部类的方法那么必须持有外部类的引用)

注意:内部类不一定会导致内存泄漏,除非执行了耗时任务外部类销毁的时候,
内部类的任务还在执行那么,执行的任务会持有内部类的引用,内部类又持有外部类的引用

public class BitmapDemo {


    public void say(){
        MyDemo demo = new MyDemo();
    }
    
    public void setName(){
        
    }
    
    class MyDemo{
        public void say(){
            setName();
        }
    }
}

2 静态内部类中存在异步任务,可能会导致其对应的外部类内存资源无法正常释放

3 静态内部类中创建了一个静态实例,会导致内存泄漏

解决方法

1 通过静态内部类来去除隐式引用

static class MyDemo{
    public void say(){
        //setName();
    }
}

2 修改静态内部类的构造方式,手动引入其外部类引用(看handler内存泄漏解决)

3 Android可以WeakReference包裹外部类实例


handler如何造成内存泄漏?如何解决?

内存泄漏的原因:非静态内部类持有外部类的引用,当activity退出的时候有可能发送的message
还在message队列里,这样就造成外部引用被持有而不能被销毁。

解决办法

public class Main2Activity extends AppCompatActivity {


private  MyHandler handler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);

  
    handler.sendEmptyMessage(1000);
}

static class MyHandler extends Handler{

    private final SoftReference<Activity> activitySoftReference;

    public MyHandler(Activity activity){
        activitySoftReference = new SoftReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        
        if (activitySoftReference != null){
            
        }
    }
}
}

什么是冷启动什么是热启动?

冷启动 :就是启动应用前,系统中没有该应用的任何进程信息(第一次启动应用,或者应用被杀死再次启动)

热启动 :用户使用返回键退出应用,然后马上又重新启动应用(进程是保留在后台的)


冷启动优化


sp问题


内存对象序列化

总结:

上一篇 下一篇

猜你喜欢

热点阅读