写点什么

2021 年 Android 高级面试题,成功入职字节跳动

发布于: 刚刚

正文

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


参考回答:首先我们要清楚图片的三级缓存是如何的



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


2.内存中如果加载一张 500X500 的 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 和链接慢,想办法复用客户端使用的域名和链接。


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


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


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

  • 比如一张 10241024 的高清图片来说。那么它占有的内存为 102410244,即 4MB,如果 inSampleSize 为 2,那么采样后的图片占用内存只有 512512*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,重新加载图片


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


参考回答:1.内存判定对象可回收有两种机制


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

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


2.GC 回收算法有以下四种:


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

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

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

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

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

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

尾声

评论里面有些同学有疑问关于如何学习 material design 控件,我的建议是去 GitHub 搜,有很多同行给的例子,这些栗子足够入门。


有朋友说要是动真格的话,需要 NDK 以及 JVM 等的知识,首现**NDK 并不是神秘的东西,**你跟着官方的步骤走一遍就知道什么回事了,无非就是一些代码格式以及原生/JAVA 内存交互,进阶一点的有原生/JAVA 线程交互,线程交互确实有点蛋疼,但平常避免用就好了,再说对于初学者来说关心 NDK 干嘛,据鄙人以前的经历,只在音视频通信和一个嵌入式信号处理(离线)的两个项目中用过,嵌入式信号处理是 JAVA->NDK->.SO->MATLAB 这样调用的我原来 MATLAB 的代码,其他的大多就用在游戏上了吧,一般的互联网公司会有人给你公司的 SO 包的。至于 JVM,该掌握的那部分,相信我,你会掌握的,不该你掌握的,有那些专门研究 JVM 的人来做,不如省省心有空看看计算机系统,编译原理。


一句话,平常多写多练,这是最基本的程序员的素质,尽量挤时间,读理论基础书籍,JVM 不是未来 30 年唯一的虚拟机,JAVA 也不一定再风靡未来 30 年工业界,其他的系统和语言也会雨后春笋冒出来,但你理论扎实会让你很快理解学会一个语言或者框架,你平常写的多会让你很快熟练的将新学的东西应用到实际中。初学者,一句话,多练。


**本文已被[CODING 开源项目:《Android 学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》](


)



收录**


最后自我介绍一下,小编 13 年上海交大毕业,曾经在小公司待过,也去过华为、OPPO 等大厂,18 年进入阿里一直到现在。

深知大多数初中级 Android 工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此也是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

用户头像

还未添加个人签名 2021.10.19 加入

还未添加个人简介

评论

发布
暂无评论
2021年Android高级面试题,成功入职字节跳动