2026-01-05 03:45:02
在 Android 性能优化面试中,因细节疏漏导致失败的情况屡见不鲜。结合面试案例与高频考点,以下从内存优化、OOM问题、UI卡顿三个核心模块梳理关键细节,并补充完整回答逻辑:
一、内存优化高频问题与回答策略1. 为什么官方建议别在onDraw创建对象?
内存抖动通过Android Studio的Memory Monitor可观察到锯齿状内存变化。
优化方案:将对象创建移至View初始化阶段(如init()方法),或使用对象池复用对象。
2. GC如何回收对象?如何确定对象可被回收?
标记-清除算法:从GC Root(如Activity、静态变量)出发标记存活对象,清除未标记对象。
分代回收:新生代(Minor GC)采用复制算法,老年代(Major GC)采用标记-整理算法。
3. 内存泄漏排查方案
静态变量持有Activity/Context(如单例模式误用)。
非静态内部类隐式持有外部类引用(如Handler、Runnable未静态化)。
未取消的注册监听(如BroadcastReceiver、EventBus)。
通过LeakCanary自动检测并生成泄漏报告。
手动验证:在onDestroy中置空可能泄漏的引用(如mHandler = null)。
使用ADB命令导出堆转储:adb shell dumpsys meminfo <package_name>。
1. OOM产生原因
堆内存不足(如加载大图未采样)。
内存泄漏导致可用内存逐渐减少。
虚拟机栈溢出(如递归过深)。
Bitmap未复用或未及时回收(recycle()在API 10+需手动调用)。
大量使用Cursor未关闭(数据库操作后必须调用close())。
2. LeakCanary工作原理
监控对象生命周期:通过ReferenceQueue监听WeakReference是否被回收。
触发GC:调用Runtime.getRuntime().gc()强制回收。
分析引用链:若对象未被回收,通过Hprof文件解析引用路径,定位泄漏源。
3. 快速解决OOM的步骤
增加堆内存(android:largeHeap="true",仅应急使用)。
压缩图片资源(使用WebP格式或inSampleSize采样)。
使用LruCache缓存Bitmap。
避免在onLowMemory()中执行耗时操作。
1. UI卡顿的根本原因
耗时操作(如IO、网络请求)未移至子线程。
复杂计算(如大数组排序)在onDraw中执行。
过度绘制(Overdraw):通过开发者选项的调试GPU过度绘制查看。
嵌套层级过深(如多层RelativeLayout嵌套)。
2. 自定义View优化技巧
避免在onDraw中创建对象或执行耗时操作。
使用invalidate()的局部重绘(通过clipRect限制区域)。
重写onMeasure时,优先使用getChildMeasureSpec传递父容器约束。
对于静态布局,可缓存测量结果(如View宽度固定时跳过测量)。
3. Fragment缓存原理
预加载相邻Fragment,避免滑动时重新创建。
默认值为1,设置过大可能导致内存占用过高。
在onDestroyView中解绑View引用(如mButton = null)。
使用FragmentManager的putFragment/getFragment管理状态。
STAR法则描述项目:
Situation:项目背景(如“用户反馈页面滑动卡顿”)。
Task:优化目标(如“将帧率稳定在55fps以上”)。
Action:具体措施(如“通过Systrace定位耗时函数,优化为异步加载”)。
Result:量化效果(如“卡顿率下降70%”)。
工具链熟练度:
必须掌握:Android Profiler、Systrace、Layout Inspector。
进阶工具:Perfetto(替代Systrace)、Jetpack Compose Profiler。
底层原理延伸:
结合Handler消息机制解释UI渲染流程。
通过Choreographer类说明帧同步原理。

总结:性能优化面试的核心在于细节深度与系统思维。需避免“会用工具但不懂原理”的表面优化,转而从内存管理、线程调度、渲染管线等底层角度构建知识体系。建议结合