性能优化性能优化是高级岗位里最容易拉开差距的部分。因为这类问题很难靠背诵过关面试官更想确认你是否真的做过“发现问题、定位根因、权衡方案、验证收益”这一整套闭环。1. 启动优化应该怎么回答才不像只会喊口号参考答案最好的回答方式不是上来就列优化手段而是先讲方法先定义当前问题是冷启动、温启动还是热启动。再拆分首帧前关键路径确认主线程、IO、类加载、三方初始化、资源加载谁在耗时。找到真正阻塞首屏的关键路径后再决定是延后、异步、懒加载、并行化还是删除。这比“我做了启动优化把很多东西异步了”更像真实工程能力。因为很多初始化虽然慢但并不在首帧关键路径上真正有价值的是识别关键路径而不是盲目并发。面试官继续追问什么为什么ContentProvider初始化常成为瓶颈启动任务并行后如何保证依赖顺序不乱首屏更快了但功能更容易空白或出错值不值追问怎么答因为ContentProvider会在Application之前初始化一旦里面做了重逻辑就会直接挤占冷启动关键路径。并行不代表乱跑通常要先做任务分级和依赖图关键依赖串行非关键任务再并行或后移。值不值得要看指标和副作用如果只是把问题从首屏挪到首次点击且用户感知更差那不算真正优化。直接套用句式“我做启动优化时不会先说异步而是先拆首帧前关键路径。因为很多任务虽然慢但不一定在用户最敏感的那段链路上真正该优先处理的是那些会直接挡住首屏出现的部分。”2. 如何区分启动慢是主线程阻塞、锁等待还是IO问题参考答案可以从调用栈、线程状态和耗时分布去判断如果主线程在执行大量业务代码或初始化逻辑通常是主线程阻塞。如果主线程栈停在锁获取处且有其他线程持锁就是锁等待。如果主线程或关键后台线程卡在磁盘、解压、读取配置、数据库初始化等位置通常是IO问题。高级回答要补一句性能问题不是只能看主线程。有时主线程自己没干重活但它在等别的线程结果用户感知一样会差。一个很容易被忽略的真实场景是单例或全局对象初始化。很多团队把它当成“随手可取的基础设施”但如果构造过程里包含同步磁盘读取、数据库访问、重对象创建甚至WebView相关调用就可能出现两种问题主线程第一次访问它直接把耗时逻辑跑在主线程上。后台线程先初始化它并持有锁主线程后续访问时被锁卡住。这类问题很适合在面试里讲因为它能说明你知道“后台线程不等于安全”真正关键的是谁在关键路径上等待谁。面试里可以这样收口“所以我判断启动问题时不只看主线程在做什么也会看主线程在等什么。很多表面上的主线程卡顿根因其实是初始化链和锁等待设计不合理。”3. 页面卡顿怎么排查别只说“用工具看一下”参考答案可以按下面的顺序讲先确认是不是持续掉帧还是偶发尖刺。再看是布局过重、绘制过重、动画过重还是主线程有长任务。如果是列表页再拆bind、图片加载、测量布局、嵌套层级和频繁刷新。最后结合线上指标和机型分布判断是不是特定设备问题。面试官真正看重的是你有没有“分层定位”的能力而不是工具名背得多。面试官继续追问什么卡顿是CPU忙还是GPU忙还是主线程在等锁为什么有些页面只在低端机卡本地流畅但线上差评很多你怎么解释追问怎么答CPU忙通常是主线程逻辑、布局计算或绑定过重GPU忙更像过度绘制、复杂动画等锁则往往在栈上能看到阻塞点。低端机更容易暴露问题是因为核心数、内存、磁盘和图形能力都更弱原本被高端机掩盖的小问题会被放大。本地流畅但线上差评多常见原因是测试机型太好、数据量太小、线上路径更复杂或者只在特定 ROM/设备上触发。直接套用句式“我排查卡顿时第一步不是看工具而是先判断责任层。因为只有先分清是主线程、布局绘制、图片链路还是锁等待后面的优化才不会变成盲调。”4.ANR、卡顿、掉帧三者怎么区分参考答案掉帧是渲染节奏跟不上显示刷新频率用户感知为不流畅。卡顿是更广义的用户操作不顺滑可能来自掉帧也可能来自主线程阻塞、列表白屏、点击无反馈。ANR是关键响应超时系统层面认定应用无响应。三者常有关联但不是同一件事。面试时能把边界讲清楚会显得你对性能和稳定性都有系统认识。5. 内存泄漏和内存抖动分别是什么怎么排查参考答案内存泄漏是对象本该被回收却仍被引用导致内存持续升高。常见场景有静态引用持有Context、匿名内部类未释放、监听器未解绑、协程或线程生命周期失控。内存抖动是短时间内频繁创建大量临时对象导致GC频繁触发虽然不一定泄漏但会明显影响流畅度。排查上可以这样说泄漏看对象为何无法释放关注引用链。抖动看对象为何频繁创建关注热点路径和分配频率。面试官继续追问什么为什么图片列表特别容易同时碰到泄漏和抖动LeakCanary能解决什么不能解决什么协程和Flow使用不当为什么也会引起泄漏Context用错为什么既可能带来泄漏也可能带来性能问题追问怎么答图片列表一边高频创建对象、一边容易持有页面和大图资源所以泄漏和抖动会一起出现。LeakCanary擅长帮你发现对象没释放的问题但它不能自动告诉你所有性能根因更不能解决短时内存峰值。协程和Flow如果生命周期绑错、一直收集不取消、闭包里持有页面对象一样会把引用链拖长。Context用错既可能让页面被长生命周期对象持有也可能把重初始化链放进不该放的地方比如高频创建WebView。实战里很容易被问到的一个细节很多候选人只会在这题里讲图片和Activity泄漏但如果你做过WebView、混合开发或埋点网络层最好补一个更工程化的例子某些团队为了拿User-Agent直接new WebView(context)。如果这里用了Activity Context而且对象释放不及时泄漏风险会上升。就算不形成长期泄漏频繁创建WebView也会带来明显内存峰值、GC压力和初始化耗时。这类例子很加分因为它同时把内存、性能和Context边界串起来了。直接套用句式“像User-Agent这种需求如果实现成频繁new WebView(context)我会把它看成一个典型的工程边界问题。因为它表面上是在拿字符串实际上却可能把内存峰值、初始化耗时和Context风险一起带进来。”6.OOM线上排查通常怎么做参考答案一个成熟的回答顺序是先分类型是Java heap、Bitmap、本地内存还是线程过多导致。看崩溃聚合机型、系统版本、页面入口、操作路径是否集中。分析大对象来源图片、缓存、序列化数据、数据库结果、WebView、地图等。检查内存回收策略是否存在过度缓存、未释放、重复解码。如果有条件结合hprof、线上监控和本地复现进一步确认。高级岗位回答不要只说“压缩图片、降低缓存”。更重要的是区分问题类型和根因。直接套用句式“我排查OOM一般不会一上来就猜图片而是先分类型再看聚合再去找大对象来源和缓存策略。因为同样叫内存溢出根因可能完全不是一回事。”7. 图片优化怎么答才更像做过参考答案图片优化通常可以从四层讲网络层是否有合适尺寸、格式、缓存策略解码层是否按目标尺寸采样避免原图直接解码内存层内存缓存、复用策略、生命周期释放渲染层避免过度绘制、避免大图频繁重绘如果你再补一句“很多线上问题不是单点而是图片尺寸、列表滑动、缓存策略和页面生命周期叠加导致的”基本就会比泛泛而谈更有说服力。直接套用句式“我讲图片优化时不会只说压缩而是会按网络、解码、内存、渲染四层去拆。因为图片问题在真实项目里往往不是单点而是会和列表滚动、缓存命中率、生命周期释放一起叠加。”7.1WebView/User-Agent获取为什么也可能是性能题参考答案这是一个很适合高级岗位拿来追问的细节题。很多人以为“获取个UA字符串不就是一行代码”但如果实现方式不对可能直接把WebView初始化链带进关键路径。典型风险是直接new WebView(context).getSettings().getUserAgentString()使用了不合适的Context高频场景重复创建WebView这会同时带来几类问题首次初始化耗时影响启动或首屏链路额外内存峰值和GC压力Activity Context使用不当带来的引用风险非主线程直接创建WebView的线程约束问题在现代项目里如果系统版本允许通常更适合优先使用WebSettings.getDefaultUserAgent(context)并尽量使用Application Context。核心原因不是“API 更新”而是它更轻、更稳也更适合放在基础能力层里复用。面试官继续追问什么为什么getUserAgentString()看起来轻量实际却可能很重为什么这类问题既算性能问题也算内存与工程边界问题首次调用虽然不一定每次都慢但为什么仍值得治理追问怎么答因为它背后可能不是简单取值而是触发了WebView相关初始化链所以成本远高于表面代码长度。它既影响启动和响应又牵涉Context、对象释放、线程限制和基础能力下沉所以不是单纯性能题。首次调用只要可能落在关键路径上就值得治理因为用户往往只在第一次进入页面时感知最强。直接套用句式“我会把这类问题定义成‘看起来轻、实际不轻’的典型案例。因为真正难的不是发现某一行代码慢而是识别出这行代码背后带出的完整初始化链。”8. 包体积优化有哪些常见手段怎么谈收益和代价参考答案包体积优化常见手段包括无用资源清理代码收缩和混淆图片资源压缩与格式替换so裁剪动态下发或模块拆分但高级回答要补上代价裁剪过头可能导致兼容性问题资源动态化会增加运行时复杂度过度依赖远端下发会影响可用性和回滚成本所以优化不能只盯着安装包数字还要看下载成功率、启动耗时、运行稳定性和业务复杂度。9. 电量优化和后台任务优化为什么现在更重要参考答案因为系统对后台限制越来越严格移动端已经不是“想什么时候跑就什么时候跑”的环境。电量优化本质上是在约束下设计任务执行策略减少无意义唤醒、轮询和常驻行为。回答时可以强调是否真的需要实时能否合并任务能否交给系统调度页面退出后是否还必须继续执行面试官继续追问什么为什么高版本系统更不鼓励后台常驻前台服务是不是万能解法同步任务如何在可靠性和耗电之间取平衡追问怎么答因为移动端资源有限后台常驻会长期占用电量、内存和系统调度资源系统自然越来越倾向限制它。前台服务不是万能解法它只是把代价显式暴露给用户并不能替代正确的任务分级和调度设计。平衡点通常是关键数据优先保证可靠性非关键任务交给系统调度或合并批量执行避免为了“保险”无脑常驻。直接套用句式“我看后台任务优化时不会先问怎么保活而是先问这件事到底是不是真的需要实时。如果目标本身就不需要常驻那最好的优化往往不是更强的保活而是压根别让它长期跑着。”10. 最强的性能回答方式是什么参考答案直接讲一个完整案例按这五步说问题现象是什么你怎么定位的根因是什么最终方案是什么指标改善了多少还有什么遗留风险例如“我们首页冷启动首屏耗时偏高先拆了主线程关键路径发现三方 SDK 和本地配置初始化挤在首帧前。后面把无首屏依赖的任务延后把部分配置读取改成惰性加载同时梳理任务依赖避免异步后反而出现等待。最终首屏耗时下降了约 25%但也留下一个风险点就是某个功能首次进入时会有一次额外初始化我们又补了埋点继续观察。”这种回答比列十个优化点更像高级工程师。面试里可以这样收口“我觉得性能优化真正有价值的地方不是记住多少技巧而是能把问题从现象拆到关键路径再从关键路径拆到真实瓶颈最后用数据证明这次改动确实值得做。”相关推荐《单例初始化中的耗时操作如何拖死主线程》《别再乱传 Context 了从源码看 WebSettings.getDefaultUserAgent(context) 的正确用法》《Android 高级工程师面试参考答案架构设计、Jetpack 与 Compose》