写点什么

Android 篇:2019 初中级 Android 开发社招面试解答(中,跨平台 app 开发框架排名

用户头像
Android架构
关注
发布于: 3 小时前
  • 参考回答:

  • 一个 Thread 只能有一个 Looper,一个 MessageQueen,可以有多个 Handler

  • 以一个线程为基准,他们的数量级关系是: Thread(1) : Looper(1) : MessageQueue(1) : Handler(N)

3、软引用跟弱引用的区别

  • 参考回答:

  • 软引用(SoftReference):如果一个对象只具有软引用,则内存空间充足时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以一直被程序使用。

  • 弱引用(WeakReference):如果一个对象只具有弱引用,那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

  • 两者之间根本区别在于:只具有弱引用的对象拥有更短暂的生命周期,可能随时被回收。而只具有软引用的对象只有当内存不够的时候才被回收,在内存足够的时候,通常不被回收。


  • 推荐文章: Java中的四种引用类型:强引用、软引用、弱引用和虚引用

4、Handler 引起的内存泄露原因以及最佳解决方案

  • 参考回答:

  • 泄露原因:

  • Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。 这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。

  • 解决方案:

  • 将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并在 Acitivity 的 onDestroy()中调用 handler.removeCallbacksAndMessages(null)及时移除所有消息。

5、为什么系统不建议在子线程访问 UI?

  • 参考回答:

  • Android 的 UI 控件不是线程安全的,如果在多线程中并发访问可能会导致 UI 控件处于不可预期的状态

  • 这时你可能会问为何系统不对 UI 控件的访问加上锁机制呢?因为

  • 加锁机制会让 UI 访问逻辑变的复杂

  • 加锁机制会降低 UI 的访问效率,因为加锁会阻塞某些线程的执行


6、Looper 死循环为什么不会导致应用卡死?

  • 参考回答:

  • 主线程的主要方法就是消息循环,一旦退出消息循环,那么你的应用也就退出了,Looer.loop()方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生 ANR 异常。

  • 造成 ANR 的不是主线程阻塞,而是主线程的 Looper 消息处理过程发生了任务阻塞,无法响应手势操作,不能及时刷新 UI。

  • 阻塞与程序无响应没有必然关系,虽然主线程在没有消息可处理的时候是阻塞的,但是只要保证有消息的时候能够立刻处理,程序是不会无响应的。

7、使用 Handler 的 postDealy 后消息队列会有什么变化?

  • 参考回答:

  • 如果队列中只有这个消息,那么消息不会被发送,而是计算到时唤醒的时间,先将 Looper 阻塞,到时间就唤醒它。但如果此时要加入新消息,该消息队列的对头跟 delay 时间相比更长,则插入到头部,按照触发时间进行排序,队头的时间最小、队尾的时间最大

8、可以在子线程直接 new 一个 Handler 吗?怎么做?

  • 参考回答:

  • 不可以,因为在主线程中,Activity 内部包含一个 Looper 对象,它会自动管理 Looper,处理子线程中发送过来的消息。而对于子线程而言,没有任何对象帮助我们维护 Looper 对象,所以需要我们自己手动维护。所以要在子线程开启 Handler 要先创建 Looper,并开启 Looper 循环


  • 推荐文章:Android异步消息处理机制完全解析,带你从源码的角度彻底理解

9、Message 可以如何创建?哪种效果更好,为什么?

  • 参考回答:可以通过三种方法创建:

  • 直接生成实例 Message m = new Message

  • 通过 Message m = Message.obtain

  • 通过 Message m = mHandler.obtainMessage()

  • 后两者效果更好,因为 Android 默认的消息池中消息数量是 10,而后两者是直接在消息池中取出一个 Message 实例,这样做就可以避免多生成 Message 实例。

线程

1、线程池的好处? 四种线程池的使用场景,线程池的几个参数的理解?

  • 参考回答:

  • 使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或则“过度切换”的问题,归纳总结就是

  • 重用存在的线程,减少对象创建、消亡的开销,性能佳。

  • 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。

  • 提供定时执行、定期执行、单线程、并发数控制等功能。

  • Android 中的线程池都是直接或间接通过配置 ThreadPoolExecutor 来实现不同特性的线程池.Android 中最常见的类具有不同特性的线程池分别为:

  • newCachedThreadPool:只有非核心线程,最大线程数非常大,所有线程都活动时会为新任务创建新线程,否则会利用空闲线程 ( 60s 空闲时间,过了就会被回收,所以线程池中有 0 个线程的可能 )来处理任务.

  • 优点:任何任务都会被立即执行(任务队列 SynchronousQuue 相当于一个空集合);比较适合执行大量的耗时较少的任务.

  • newFixedThreadPool:只有核心线程,并且数量固定的,所有线程都活动时,因为队列没有限制大小,新任务会等待执行,当线程池空闲时不会释放工作线程,还会占用一定的系统资源。

  • 优点:更快的响应外界请求

  • newScheduledThreadPool:核心线程数固定,非核心线程(闲着没活干会被立即回收数)没有限制.

  • 优点:执行定时任务以及有固定周期的重复任务

  • newSingleThreadExecutor:只有一个核心线程,确保所有的任务都在同一线程中按序完成

  • 优点:不需要处理线程同步的问题

  • 通过源码可以了解到上面的四种线程池实际上还是利用 ThreadPoolExecutor 类实现的


  • 推荐文章:java线程池解析和四种线程池的使用

2、Android 中还了解哪些方便线程切换的类?

  • 参考回答:

  • AsyncTask:底层封装了线程池和 Handler,便于执行后台任务以及在子线程中进行 UI 操作。

  • HandlerThread:一种具有消息循环的线程,其内部可使用 Handler。

  • IntentService:是一种异步、会自动停止的服务,内部采用 HandlerThread。

3、讲讲 AsyncTask 的原理

  • 参考回答:

  • AsyncTask 中有两个线程池(SerialExecutor 和 THREAD_POOL_EXECUTOR)和一个 Handler(InternalHandler),其中线程池 SerialExecutor 用于任务的排队,而线程池 THREAD_POOL_EXECUTOR 用于真正地执行任务,InternalHandler 用于将执行环境从线程池切换到主线程。

  • sHandler 是一个静态的 Handler 对象,为了能够将执行环境切换到主线程,这就要求 sHandler 这个对象必须在主线程创建。由于静态成员会在加载类的时候进行初始化,因此这就变相要求 AsyncTask 的类必须在主线程中加载,否则同一个进程中的 AsyncTask 都将无法正常工作。

4、IntentService 有什么用 ?

  • 参考回答:

  • IntentService 可用于执行后台耗时的任务,当任务执行完成后会自动停止,同时由于 IntentService 是服务的原因,不同于普通 Service,IntentService 可自动创建子线程来执行任务,这导致它的优先级比单纯的线程要高,不容易被系统杀死,所以 IntentService 比较适合执行一些高优先级的后台任务。

5、直接在 Activity 中创建一个 thread 跟在 service 中创建一个 thread 之间的区别?

  • 参考回答:

  • 在 Activity 中被创建:该 Thread 的就是为这个 Activity 服务的,完成这个特定的 Activity 交代的任务,主动通知该 Activity 一些消息和事件,Activity 销毁后,该 Thread 也没有存活的意义了。

  • 在 Service 中被创建:这是保证最长生命周期的 Thread 的唯一方式,只要整个 Service 不退出,Thread 就可以一直在后台执行,一般在 Service 的 onCreate()中创建,在 onDestroy()中销毁。所以,在 Service 中创建的 Thread,适合长期执行一些独立于 APP 的后台任务,比较常见的就是:在 Service 中保持与服务器端的长连接。

6、ThreadPoolExecutor 的工作策略 ?

  • 参考回答:ThreadPoolExecutor 执行任务时会遵循如下规则

  • 如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。

  • 如果线程池中的线程数量已经达到或则超过核心线程的数量,那么任务会被插入任务队列中排队等待执行。

  • 如果在第 2 点无法将任务插入到任务队列中,这往往是由于任务队列已满,这个时候如果在线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务。

  • 如果第 3 点中线程数量已经达到线程池规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor 会调用 RejectedExecutionHandler 的 rejectedExecution 方法来通知调用者。

7、Handler、Thread 和 HandlerThread 的差别?

  • 参考回答:

  • Handler:在 android 中负责发送和处理消息,通过它可以实现其他支线线程与主线程之间的消息通讯。

  • Thread:Java 进程中执行运算的最小单位,亦即执行处理机调度的基本单位。某一进程中一路单独运行的程序。

  • HandlerThread:一个继承自 Thread 的类 HandlerThread,Android 中没有对 Java 中的 Thread 进行任何封装,而是提供了一个继承自 Thread 的类 HandlerThread 类,这个类对 Java 的 Thread 做了很多便利的封装。HandlerThread 继承于 Thread,所以它本质就是个 Thread。与普通 Thread 的差别就在于,它在内部直接实现了 Looper 的实现,这是 Handler 消息机制必不可少的。有了自己的 looper,可以让我们在自己的线程中分发和处理消息。如果不用 HandlerThread 的话,需要手动去调用 Looper.prepare()和 Looper.loop()这些方法。

8、ThreadLocal 的原理

  • 参考回答:

  • ThreadLocal 是一个关于创建线程局部变量的类。使用场景如下所示:

  • 实现单个线程单例以及单个线程上下文信息存储,比如交易 id 等。

  • 实现线程安全,非线程安全的对象使用 ThreadLocal 之后就会变得线程安全,因为每个线程都会有一个对应的实例。 承载一些线程相关的数据,避免在方法中来回传递参数。

  • 当需要使用多线程时,有个变量恰巧不需要共享,此时就不必使用 synchronized 这么麻烦的关键字来锁住,每个线程都相当于在堆内存中开辟一个空间,线程中带有对共享变量的缓冲区,通过缓冲区将堆内存中的共享变量进行读取和操作,ThreadLocal 相当于线程内的内存,一个局部变量。每次可以对线程自身的数据读取和操作,并不需要通过缓冲区与 主内存中的变量进行交互。并不会像 synchronized 那样修改主内存的数据,再将主内存的数据复制到线程内的工作内存。ThreadLocal 可以让线程独占资源,存储于线程内部,避免线程堵塞造成 CPU 吞吐下降。

  • 在每个 Thread 中包含一个 ThreadLocalMap,ThreadLocalMap 的 key 是 ThreadLocal 的对象,value 是独享数据。

9、多线程是否一定会高效(优缺点)

  • 参考回答:

  • 多线程的优点:

  • 方便高效的内存共享 - 多进程下内存共享比较不便,且会抵消掉多进程编程的好处

  • 较轻的上下文切换开销 - 不用切换地址空间,不用更改 CR3 寄存器,不用清空 TLB

  • 线程上的任务执行完后自动销毁

  • 多线程的缺点:

  • 开启线程需要占用一定的内存空间(默认情况下,每一个线程都占 512KB)

  • 如果开启大量的线程,会占用大量的内存空间,降低程序的性能

  • 线程越多,cpu 在调用线程上的开销就越大

  • 程序设计更加复杂,比如线程间的通信、多线程的数据共享

  • 综上得出,多线程不一定能提高效率,在内存空间紧张的情况下反而是一种负担,因此在日常开发中,应尽量

  • 不要频繁创建,销毁线程,使用线程池

  • 减少线程间同步和通信(最为关键)

  • 避免需要频繁共享写的数据

  • 合理安排共享数据结构,避免伪共享(false sharing)

  • 使用非阻塞数据结构/算法

  • 避免可能产生可伸缩性问题的系统调用(比如 mmap)

  • 避免产生大量缺页异常,尽量使用 Huge Page

  • 可以的话使用用户态轻量级线程代替内核线程

10、多线程中,让你做一个单例,你会怎么做

  • 参考回答:

  • 多线程中建立单例模式考虑的因素有很多,比如线程安全 -延迟加载-代码安全:如防止序列化攻击,防止反射攻击(防止反射进行私有方法调用) -性能因素

  • 实现方法有多种,饿汉,懒汉(线程安全,线程非安全),双重检查(DCL),内部类,以及枚举


  • 推荐文章:单例模式的总结

11、除了 notify 还有什么方式可以唤醒线程

  • 参考回答:

  • 当一个拥有 Object 锁的线程调用 wait()方法时,就会使当前线程加入 object.wait 等待队列中,并且释放当前占用的 Object 锁,这样其他线程就有机会获取这个 Object 锁,获得 Object 锁的线程调用 notify()方法,就能在 Object.wait 等待队列中随机唤醒一个线程(该唤醒是随机的与加入的顺序无关,优先级高的被唤醒概率会高)

  • 如果调用 notifyAll()方法就唤醒全部的线程。注意:调用 notify()方法后并不会立即释放 object 锁,会等待该线程执行完毕后释放 Object 锁。

12、什么是 ANR ? 什么情况会出现 ANR ?如何避免 ? 在不看代码的情况下如何快速定位出现 ANR 问题所在 ?

  • 参考回答:

  • ANR(Application Not Responding,应用无响应):当操作在一段时间内系统无法处理时,会在系统层面会弹出 ANR 对话框

  • 产生 ANR 可能是因为 5s 内无响应用户输入事件、10s 内未结束 BroadcastReceiver、20s 内未结束 Service

  • 想要避免 ANR 就不要在主线程做耗时操作,而是通过开子线程,方法比如继承 Thread 或实现 Runnable 接口、使用 AsyncTask、IntentService、HandlerThread 等

  • 推荐文章:如何快速分析定位ANR

Bitmap

1、Bitmap 使用需要注意哪些问题 ?

  • 参考回答:

  • 要选择合适的图片规格(bitmap 类型):通常我们优化 Bitmap 时,当需要做性能优化或者防止 OOM,我们通常会使用 RGB_565,因为 ALPHA_8 只有透明度,显示一般图片没有意义,Bitmap.Config.ARGB_4444 显示图片不清楚,Bitmap.Config.ARGB_8888 占用内存最多。:

  • ALPHA_8 每个像素占用 1byte 内存


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


*   ARGB\_4444 每个像素占用2byte内存
复制代码


    *   ARGB\_8888 每个像素占用4byte内存(默认)
    *   RGB\_565 每个像素占用2byte内存
*   **降低采样率**:BitmapFactory.Options 参数inSampleSize的使用,先把options.inJustDecodeBounds设为true,只是去读取图片的大小,在拿到图片的大小之后和要显示的大小做比较通过calculateInSampleSize()函数计算inSampleSize的具体值,得到值之后。options.inJustDecodeBounds设为false读图片资源。
*   **复用内存**:即通过软引用(内存不够的时候才会回收掉),复用内存块,不需要再重新给这个bitmap申请一块新的内存,避免了一次内存的分配和回收,从而改善了运行效率。
*   **使用recycle()方法及时回收内存**。
*   **压缩图片**。

2、Bitmap.recycle()会立即回收么?什么时候会回收?如果没有地方使用这个 Bitmap,为什么垃圾回收不会直接回收?

  • 参考回答:

  • 通过源码可以了解到,加载 Bitmap 到内存里以后,是包含两部分内存区域的。简单的说,一部分是 Java 部分的,一部分是 C 部分的。这个 Bitmap 对象是由 Java 部分分配的,不用的时候系统就会自动回收了

  • 但是那个对应的 C 可用的内存区域,虚拟机是不能直接回收的,这个只能调用底层的功能释放。所以需要调用 recycle()方法来释放 C 部分的内存

  • bitmap.recycle()方法用于回收该 Bitmap 所占用的内存,接着将 bitmap 置空,最后使用 System.gc()调用一下系统的垃圾回收器进行回收,调用 System.gc()并不能保证立即开始进行回收过程,而只是为了加快回收的到来。

3、一张 Bitmap 所占内存以及内存占用的计算

  • 参考回答:

  • Bitamp 所占内存大小 = 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存字节大小

  • 注:这里 inDensity 表示目标图片的 dpi(放在哪个资源文件夹下),inTargetDensity 表示目标屏幕的 dpi,所以你可以发现 inDensity 和 inTargetDensity 会对 Bitmap 的宽高进行拉伸,进而改变 Bitmap 占用内存的大小。

  • 在 Bitmap 里有两个获取内存占用大小的方法。

  • getByteCount():API12 加入,代表存储 Bitmap 的像素需要的最少内存。

  • getAllocationByteCount():API19 加入,代表在内存中为 Bitmap 分配的内存大小,代替了 getByteCount() 方法。

  • 不复用 Bitmap 时,getByteCount() 和 getAllocationByteCount 返回的结果是一样的。在通过复用 Bitmap 来解码图片时,那么 getByteCount() 表示新解码图片占用内存的大 小,getAllocationByteCount() 表示被复用 Bitmap 真实占用的内存大小

4、Android 中缓存更新策略 ?

  • 参考回答:

  • Android 的缓存更新策略没有统一的标准,一般来说,缓存策略主要包含缓存的添加、获取和删除这三类操作,但不管是内存缓存还是存储设备缓存,它们的缓存容量是有限制的,因此删除一些旧缓存并添加新缓存,如何定义缓存的新旧这就是一种策略,不同的策略就对应着不同的缓存算法

  • 比如可以简单地根据文件的最后修改时间来定义缓存的新旧,当缓存满时就将最后修改时间较早的缓存移除,这就是一种缓存算法,但不算很完美

5、LRU 的原理 ?

  • 参考回答:

  • 为减少流量消耗,可采用缓存策略。常用的缓存算法是 LRU(Least Recently Used):当缓存满时, 会优先淘汰那些近期最少使用的缓存对象。主要是两种方式:

  • LruCache(内存缓存):LruCache 类是一个线程安全的泛型类:内部采用一个 LinkedHashMap 以强引用的方式存储外界的缓存对象,并提供 get 和 put 方法来完成缓存的获取和添加操作,当缓存满时会移除较早使用的缓存对象,再添加新的缓存对象。

  • DiskLruCache(磁盘缓存): 通过将缓存对象写入文件系统从而实现缓存效果

性能优化

1、图片的三级缓存中,图片加载到内存中,如果内存快爆了,会发生什么?怎么处理?

  • 参考回答:

  • 首先我们要清楚图片的三级缓存是如何的


  • 如果内存足够时不回收。内存不够时就回收软引用对象

2、内存中如果加载一张 500*500 的 png 高清图片.应该是占用多少的内存?

  • 参考回答:

  • 不考虑屏幕比的话:占用内存=500 * 500 * 4 = 1000000B ≈ 0.95MB

  • 考虑屏幕比的的话:占用内存= 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存字节大小

  • inDensity 表示目标图片的 dpi(放在哪个资源文件夹下),inTargetDensity 表示目标屏幕的 dpi


3、WebView 的性能优化 ?

  • 参考回答:

  • 一个加载网页的过程中,native、网络、后端处理、CPU 都会参与,各自都有必要的工作和依赖关系;让他们相互并行处理而不是相互阻塞才可以让网页加载更快:

  • WebView 初始化慢,可以在初始化同时先请求数据,让后端和网络不要闲着。

  • 常用 JS 本地化及延迟加载,使用第三方浏览内核

  • 后端处理慢,可以让服务器分 trunk 输出,在后端计算的同时前端也加载网络静态资源。

  • 脚本执行慢,就让脚本在最后运行,不阻塞页面解析。

  • 同时,合理的预加载、预缓存可以让加载速度的瓶颈更小。

  • WebView 初始化慢,就随时初始化好一个 WebView 待用。

  • DNS 和链接慢,想办法复用客户端使用的域名和链接。


  • 推荐文章:WebView性能、体验分析与优化

4、Bitmap 如何处理大图,如一张 30M 的大图,如何预防 OOM?

  • 参考回答:避免 OOM 的问题就需要对大图片的加载进行管理,主要通过缩放来减小图片的内存占用。

  • BitmapFactory 提供的加载图片的四类方法(decodeFile、decodeResource、decodeStream、decodeByteArray)都支持 BitmapFactory.Options 参数,通过 inSampleSize 参数就可以很方便地对一个图片进行采样缩放

  • 比如一张 1024_1024 的高清图片来说。那么它占有的内存为 1024_1024_4,即 4MB,如果 inSampleSize 为 2,那么采样后的图片占用内存只有 512_512*4,即 1MB(注意:根据最新的官方文档指出,inSampleSize 的取值应该总是为 2 的指数,即 1、2、4、8 等等,如果外界输入不足为 2 的指数,系统也会默认选择最接近 2 的指数代替,比如 2

  • 综合考虑。通过采样率即可有效加载图片,流程如下

  • 将 BitmapFactory.Options 的 inJustDecodeBounds 参数设为 true 并加载图片

  • 从 BitmapFactory.Options 中取出图片的原始宽高信息,它们对应 outWidth 和 outHeight 参数

  • 根据采样率的规则并结合目标 View 的所需大小计算出采样率 inSampleSize

  • 将 BitmapFactory.Options 的 inJustDecodeBounds 参数设为 false,重新加载图片


  • 推荐文章:Android高效加载大图、多图解决方案,有效避免程序OOM

5、内存回收机制与 GC 算法(各种算法的优缺点以及应用场景);GC 原理时机以及 GC 对象

  • 参考回答:

  • 内存判定对象可回收有两种机制:

  • 引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加 1;当引用失效时,计数器值就减 1;任何时刻计数器为 0 的对象就是不可能再被使用的。然而在主流的 Java 虚拟机里未选用引用计数算法来管理内存,主要原因是它难以解决对象之间相互循环引用的问题,所以出现了另一种对象存活判定算法。

  • 可达性分析法:通过一系列被称为『GCRoots』的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为_引用链,当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的。其中可作为 GC Roots 的对象:虚拟机栈中引用的对象,主要是指栈帧中的__本地变量_*、本地方法栈中 Native 方法引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象

  • GC 回收算法有以下四种:

  • 分代收集算法:是当前商业虚拟机都采用的一种算法,根据对象存活周期的不同,将 Java 堆划分为新生代和老年代,并根据各个年代的特点采用最适当的收集算法。

  • 新生代:大批对象死去,只有少量存活。使用『复制算法』,只需复制少量存活对象即可。

  • 复制算法:把可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用尽后,把还存活着的对象『复制』到另外一块上面,再将这一块内存空间一次清理掉。实现简单,运行高效。在对象存活率较高时就要进行较多的复制操作,效率将会变低

  • 老年代:对象存活率高。使用『标记—清理算法』或者『标记—整理算法』,只需标记较少的回收对象即可。

  • 标记-清除算法:首先『标记』出所有需要回收的对象,然后统一『清除』所有被标记的对象。标记和清除两个过程的效率都不高,清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

  • 标记-整理算法:首先『标记』出所有需要回收的对象,然后进行『整理』,使得存活的对象都向一端移动,最后直接清理掉端边界以外的内存。标记整理算法会将所有的存活对象移动到一端,并对不存活对象进行处理,因此其不会产生内存碎片

  • 推荐文章:图解Java 垃圾回收机制

6、内存泄露和内存溢出的区别 ?AS 有什么工具可以检测内存泄露

  • 参考回答:

  • 内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory;比如申请了一个 integer,但给它存了 long 才能存下的数,那就是内存溢出。

  • 内存泄露(memory leak):是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak 会最终会导致 out of memory!

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android篇:2019初中级Android开发社招面试解答(中,跨平台app开发框架排名