Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 358|回复: 0

第8章 Android异常与性能优化相关面试问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-5-14 19:30:33 | 显示全部楼层 |阅读模式

    1、anr异常面试问题讲解

      a)  什么是anr?

        应用程序无响应对话框

      b)  造成anr的原因?

        主线程中做了耗时操作

      c)  android中那些操作是在主线程呢?

        activity的所有生命周期回调都是执行在主线程的

        Service默认是执行在主线程的

        BroadcastReceiver的onReceiver回调是执行在主线程的

        没有使用子线程的Looper的Handler的handlerMessage,post(Runnable)是执行在主线程的

        AsyncTask的回调中除了doInBackground,其它都是执行在主线程

      d)  如何解决anr

        使用AsyncTask处理耗时IO操作

        使用Thread或者HandlerThread提高优先级

        使用handler来处理工作线程的耗时任务

        activity的onCreate和onResume回调中尽量避免耗时的代码

     

    2、oom异常面试问题讲解

      a)  什么是oom ?

        当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出的Out  of  memory异常 

      b)  一些容易混淆的概念

       内存溢出 / 内存抖动 / 内存泄漏

       内存溢出:就是oom

       内存抖动:短时间内大量对象被创建然后马上被释放

       内存泄漏:当程序不再使用到的内存时,释放内存失败而产生了无用的内存消耗

      d) 如何解决oom

       1.有关bitmap优化

        图片显示(比如监听listview滑动,停止的时候加载大图)

        及时释放内存

          bitmap的够着方法都是私有的,通过BitmapFactory生成Bitmap到内存中都是通过jni实现的,简单点说会有俩部分区域,一部分是java区,一部分是C区,但是Bitmap是通过java分配的,不用的时候也是由java的gc机制回收的。对应C区域不能及时回收的,所以这里说的释放内存就是释放的c的那块区域(通过

    recycle方法,该方法内部调用了jni的方法)。要是不释放只能等进程死了以后就会被释放
       图片压缩
       inBitmap属性(图片复用)
       捕获异常   

       2.其它方法

        listview:convertview / lru(三级缓存)

        避免在onDraw方法里面执行对象的创建

        谨慎使用多进程

     

    3、 bitmap面试问题讲解

      a)  recycle :释放bitmap内存的时候会释放所对应的native的内存,但是不会立即释放,但是调用完就不能使用该bitmap了,是不可逆的。官方不建议主动调用。垃圾回收器主动会清理。

      b)  LRU:三级缓存,内部是通过map实现的,里面提供了put、get方法来完成缓存的添加和获取操作。当缓存满的时候,lru算法会提供trimToSize删除最久或者使用最少的缓存对象,添加新的缓存对象

      c)  计算inSampleSize:

      d)  缩略图

        

     /**
         * 获取缩略图
         * @param imagePath:文件路径
         * @param width:缩略图宽度
         * @param height:缩略图高度
         * @return
         */
        public static Bitmap getImageThumbnail(String imagePath, int width, int height) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true; //关于inJustDecodeBounds的作用将在下文叙述
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
            int h = options.outHeight;//获取图片高度
            int w = options.outWidth;//获取图片宽度
            int scaleWidth = w / width; //计算宽度缩放比
            int scaleHeight = h / height; //计算高度缩放比
            int scale = 1;//初始缩放比
            if (scaleWidth < scaleHeight) {//选择合适的缩放比
                scale = scaleWidth;
            } else {
                scale = scaleHeight;
            }
            if (scale <= 0) {//判断缩放比是否符合条件
                be = 1;
            }
            options.inSampleSize = scale;
            // 重新读入图片,读取缩放后的bitmap,注意这次要把inJustDecodeBounds 设为 false
                    options.inJustDecodeBounds = false;
                    bitmap = BitmapFactory.decodeFile(imagePath, options);
            // 利用ThumbnailUtils来创建缩略图,这里要指定要缩放哪个Bitmap对象
            bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
            return bitmap;
        }

     

      e)  三级缓存

        网络、本地、内存三级缓存,减少流量的使用

     

    4、 ui卡顿面试问题讲解

      a)  UI卡顿的原理

        60fps -> 16ms    

        overdraw过度绘制 

      b)  UI卡顿的原因分析

        1.人为在UI线程中做轻微耗时操作,导致UI线程卡顿

        2.布局Layout过于复杂,无法在16ms内完成渲染

        3.同一时间动画执行的次数过多,导致CPU、GPU的负载过重

        4.View的过度绘制,导致某些像素在同一帧内被绘制多次,从而使CPU、GPU的负载过重

        5.View频繁的触发measure、layout,导致measure、layout累计耗时过多及整个View频繁的重新渲染

        6.内存频繁触发gc过多,导致暂时阻塞渲染操作

        7.冗余资源及逻辑等导致加载和执行的缓慢

        8.ANR

      c)  UI卡顿总结

        1.布局优化

        2.列表及adapter优化

        3.背景和图片等内存分配优化

        4.避免ANR

     

    4、 内存泄漏

      a)  java内存泄漏基础知识

        1.  java内存的分配策略

          静态存储区(方法区):主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好,并且在程序整个运行期间都存在。

          栈区:当方法被执行时,方法体内的局部变量(其中包括基础数据类型、对象的引用)都在栈上创建,并在方法执行结束时这些局部变量所持有的内存将会自动被释放。因为栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

          堆区 : 又称动态内存分配,通常就是指在程序运行时直接 new 出来的内存,也就是对象的实例。这部分内存在不使用时将会由 Java 垃圾回收器来负责回收。

        2.  java是如何管理内存的

              

     

        3.  java中的内存泄漏

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

      b)  android内存泄漏

        1. 单例

          

    public class AppManager {
    
        private Context mContext;
        private static AppManager instance;
    
        private AppManager(Context context){
            //有内存泄漏的问题:传入的是actiivty的context,导致activity没法释放
            //this.mContext = context;
            //所以这里应该传入Application全局的context
            this.mContext = context.getApplicationContext();
        }
    
        public static AppManager getInstance(Context context){
            if(instance ==null){
                instance = new AppManager(context);
            }
            return instance;
        }
    
    }

        2.匿名内部类 

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
    
        //这样的写法就会造成内存泄漏
        //原因是这样写法虽然避免了重复创建,但是非静态内部类持有外部类的引用,
        //这时候我们又创建了一个静态实例TAG的话就会和应用的生命周期一样长,所以就会使外部的activity没法释放
        class TestResource{
            private static final String TAG = "";
        }
        
        //正常的写法,这样的话就不会持有外部类的引用。
        static class TestResource1{
            private static final String TAG = "";
        }
    
    }
    

        3.handler

    public class MainActivity extends AppCompatActivity {
    
    
        private TextView mTv;
        private MyHandler myHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            myHandler = new MyHandler(this);
        }
    
    
    
        //这样的写法会造成内存泄漏
        //mHandler是MainActivity的非静态内部类的实例,它持有外部类的引用,我们知道handler的消息是在一个loop
        //中不断的轮询处理消息,那么当MainActivity退出时,消息队列中还有没处理的消息或正在处理的消息,所以会造成内存泄漏
       @SuppressLint("HandlerLeak")
       private Handler mHandler = new Handler(){
           @Override
           public void handleMessage(Message msg) {
               super.handleMessage(msg);
           }
       };
    
        //这样写是正确的写法
        static class MyHandler extends Handler{
    
            //创建一个软引用
            private WeakReference<Context> reference;
    
            public MyHandler(Context context){
                reference = new WeakReference<Context>(context);
            }
    
            @Override
            public void handleMessage(Message msg) {
                MainActivity mainActivity = (MainActivity) reference.get();
                if(mainActivity != null){
                    //TODO------
                    mainActivity.mTv.setText("11");
                }
            }
        }
      @Override
      protected void onDestroy() {
      super.onDestroy();
      myHandler.removeCallbacksAndMessages(null);
      }
    }

        4.避免使用static静态变量

          如果声明成静态变量,那么它的生命周期就会和app的生命周期一样长,假如你的app是常驻后台的,即使app退到后台,这部分也不会释放

        5.资源未关闭造成的内存泄漏

        6.AsyncTask造成的内存泄漏

          在onDestory调用cancel()方法

          添加弱引用实现

     

    5、内存管理面试问题

      a)内存管理机制概述

        1.分配机制

        2.回收机制

      b)Android内存管理机制

        1.分配机制

          弹性的分配机制,当发现内存不够用的时候回分配额外的内存。但是额外的内存也不是无限量的。(让更多的进程存活在系统中)

        2.回收机制

          前台进程   可见进程   服务进程    后台进程     空进程

      c)内存管理机制的特点(目标)  

        1.更少占用的内存

        2.在合适的时候,合理的释放系统资源

        3.在系统内存紧张的情况下,能释放掉不部分不重要的资源,来为android系统提供可用的内存

        4.能够很合理的在特殊的生命周期中,保存或者还原重要数据,以至于系统能够正确的重新恢复该应用      

      d)内存优化方法

        1.当service完成任务后,尽量停止它

        2.在UI不可见的时候,释放掉一些只有UI使用的资源

        3.在系统资源紧张的时候,尽可能多的释放掉一些非重要资源

        4.避免滥用Bitmap导致的内存浪费

        5.使用针对内存优化过的数据容器

        6.避免使用依赖注入的框架

        7.使用ZIP对齐的APK

        8.使用多进程

      d)内存溢出VS内存泄漏

     

    6、冷启动优化面试问题讲解

      a)什么是冷启动?

        1.冷启动的定义

           冷启动就是在启动应用前,系统没有该应用的任何进程信息

        2.冷启动 / 热启动的区别

           热启动:用户使用返回键退出应用,然后马上又重新启动应用

           区别:

              1). 定义

              2). 启动特点

                  冷启动:Application  ->  MainActivity ->UI的绘制

                  热启动:MainActivity ->UI的绘制

        3.冷启动时间的计算

           这个时间值从应用启动(创建进程)开始计算,到完成视图的第一次绘制(即Activity内容对用户可见)为止

      b)冷启动流程

        Zygote进程中fork创建一个新的进程

        创建和初始化Application类,创建MainActivity类

        inflate布局,当onCreate / onStart / onResume方法都走完

        contentView的measure / layout /draw  显示在界面上

      c)如何对冷启动的时间进行优化

        1.减少onCreate的工作量

        2.不要让Application参与业务的操作

        3.不要在Application进行耗时操作

        4.不要以静态变量的方式在Application中保存数据

        5.布局

        6.mainThread

      d)冷启动流程-----总结

        Application的构造方法-------->attachBaseContext () --------->  onCreate () ----------->Activity的构造方法------------> onCreate () ------------>  配置主题中背景等属性------------->onStart () ---------> onResume() --------> 测量布局绘制显示在界面上

    7、其他优化面试问题讲解

      a)android 不用静态变量存储数据

        1.静态变量等数据由于进程已经被杀死而被初始化

        2.使用其它的数据传输方式:文件 / sp / contentProvider

      b)有关Sharepreference的安全问题

        1.不能跨进程同步数据读写

        2.存储Sharepreference的文件过大问题

          过大的话会读取缓慢,造成UI卡顿

          读取频繁的key和不易变动的key不要放在一起

      c)内存对象序列化

       序列化:将对象的状态信息转化为可以存储或传输的形式的过程

       1.实现Serializable接口(会产生大量的临时变量,频繁的垃圾回收,这样会造成UI卡顿,内存抖动,) 

       2.实现Parcelable接口 

        总结:1>.Serializable是Java的序列化方式,Parcelable是android特有的序列化方式

           2>.在使用内存的时候,Parcelable比Serializable性能高

           3>.Serializable序列化的时候会产生大量的临时变量,从而引起频繁的GC

             4>.Parcelable不能使用在要数据存储在磁盘上的情况

      d)避免在UI线程中做繁重的操作

        

        

           

            

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-6 16:29 , Processed in 0.070489 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表