Android 高级工程师面试:JVM 内存与 GC 近1年高频追问 22 题
文章目录
- 学习建议
- 基础层(8 题)
- #1 JVM / Android 运行时内存怎么分区? 🔥
- 标准回答
- 面试官可能继续追问
- #2 堆和栈分别存什么?有什么区别? 🔥
- 标准回答
- 面试官可能继续追问
- #3 对象在内存中如何创建? ⭐
- 标准回答
- 面试官可能继续追问
- #4 什么是 GC?Android 为什么需要 GC? ⭐
- 标准回答
- 面试官可能继续追问
- #5 Minor GC 和 Full GC 有什么区别? 🔥
- 标准回答
- 面试官可能继续追问
- #6 OOM 有哪些常见类型? 🔥
- 标准回答
- 面试官可能继续追问
- #7 `StackOverflowError` 和 OOM 有什么区别? ⭐
- 标准回答
- 面试官可能继续追问
- #8 方法区 / 元空间存什么?Android 里怎么理解? ⭐
- 标准回答
- 面试官可能继续追问
- 进阶层(7 题)
- #9 常见 GC 算法有哪些? ⭐
- 标准回答
- 面试官可能继续追问
- #10 ART 的 GC 和 JVM HotSpot 有什么差异? ⭐
- 标准回答
- 面试官可能继续追问
- #11 内存泄漏和内存溢出有什么区别? 🔥
- 标准回答
- 面试官可能继续追问
- #12 Android 内存泄漏排查的一般流程? 🔥
- 标准回答
- 面试官可能继续追问
- #13 LeakCanary 的原理是什么? 🔥
- 标准回答
- 面试官可能继续追问
- #14 Bitmap 为什么容易导致 OOM? 🔥
- 标准回答
- 面试官可能继续追问
- #15 Android Studio Profiler 的 Memory 面板怎么看? ⭐
- 标准回答
- 面试官可能继续追问
- 核心层(7 题)
- #16 强软弱虚引用分别是什么?用在哪? 💡
- 标准回答
- 面试官可能继续追问
- #17 GC Roots 有哪些? 💡
- 标准回答
- 面试官可能继续追问
- #18 分代收集的思想是什么? 💡
- 标准回答
- 面试官可能继续追问
- #19 heap dump 分析的具体步骤? ⭐
- 标准回答
- 面试官可能继续追问
- #20 `android:largeHeap` 能解决内存问题吗? ⭐
- 标准回答
- 面试官可能继续追问
- #21 Android 内存优化有哪些工程实践? 🔥
- 标准回答
- 面试官可能继续追问
- #22 Finalizer 和 Cleaner 还有必要了解吗? 💡
- 标准回答
- 面试官可能继续追问
- 面试策略速查
- 必背知识(🔥)
- 高频追问
- 加分项(💡)
- 容易踩坑
- 完整链路一句通
- 相关推荐
学习建议
| 目标层级 | 建议 |
|---|---|
| 初级 | 掌握基础层 8 题:堆栈区别、OOM 类型、GC 基本概念;工程联想看追问第 1 条 |
| 中级 | 通读全文;进阶层能讲清泄漏 vs 溢出、LeakCanary 原理、Profiler 看分配曲线 |
| 高级 | 核心层加分项必答:引用类型、GC Roots、分代思想;能串联「分配→GC→泄漏→dump 分析→优化」链路 |
基础层(8 题)
#1 JVM / Android 运行时内存怎么分区? 🔥
标准回答
逻辑上分:线程私有区(程序计数器、虚拟机栈、本地方法栈)与线程共享区(堆、方法区/元空间)。
面试官可能继续追问
Android 运行时内存怎么理解?
应用跑在 ART 上,开发者主要关心堆(对象实例)、栈(方法帧与局部变量)及 Native 堆(Bitmap 像素、SO 库)。ART 和 JVM 内存模型完全一样吗?
概念相近但实现不同,ART 有专用分配器与并发 GC,别照搬 HotSpot 细节。程序计数器会 OOM 吗?
不会,区域很小;OOM 多发生在堆或 Native 分配。
#2 堆和栈分别存什么?有什么区别? 🔥
标准回答
栈:线程私有,存栈帧、局部变量表、操作数栈,方法结束自动回收。堆:线程共享,存对象实例与数组,由 GC 回收。
面试官可能继续追问
Android 里堆和栈分别存什么?
Activity局部变量引用在栈,实际对象在堆;把大对象引用传出作用域不当会导致堆泄漏。基本类型一定在栈上吗?
局部基本类型在栈;作为对象字段则随对象在堆。栈溢出是什么场景?
无限递归或过深调用链,抛StackOverflowError,不是堆 OOM。
#3 对象在内存中如何创建? ⭐
标准回答
典型路径:类加载检查 → 分配堆内存(指针碰撞/空闲列表)→ 零值初始化 → 设置对象头 →<init>构造。逃逸分析可能栈上分配或标量替换(JIT 优化,面试提及即可)。
面试官可能继续追问
Android 里对象创建要注意什么?
RecyclerViewViewHolder、临时StringBuilder等高频创建应复用,减少分配压力与 GC 抖动。对象头里有什么?
Mark Word(哈希、锁、GC 年龄)和类型指针等,知道影响锁与 GC 即可。为什么频繁
new会卡?
增加分配与 GC 负担,主线程 GC 停顿可致掉帧。
#4 什么是 GC?Android 为什么需要 GC? ⭐
标准回答
GC(垃圾回收)自动识别并回收不再可达的对象,释放堆空间。托管语言开发者不手动free,靠运行时回收避免大部分悬垂指针。代价是 STW 停顿与 CPU 开销。
面试官可能继续追问
Android 为什么需要 GC?
Java/Kotlin 靠 ART 自动回收;工程上通过少分配、避泄漏、合理图片尺寸来降低 GC 频率。不 GC 会怎样?
堆耗尽最终 OOM,应用崩溃。能手动触发 GC 吗?
System.gc()只是建议,不可依赖;应修泄漏而非逼 GC。
#5 Minor GC 和 Full GC 有什么区别? 🔥
标准回答
Minor GC:通常回收新生代(或 ART 等价年轻代区域),频繁但较快。Full GC:整堆或更大范围回收,停顿更长。频繁 Full GC 是性能红灯。
面试官可能继续追问
Android 里怎么判断 Full GC?
用 Profiler 看 Memory 时间线,若伴随卡顿且分配骤降,可能在全量回收;应查大对象与泄漏而非只盯日志标签。怎么从 Logcat 判断 GC?
看GC/Explicit日志与分配量,结合 Systrace/Profiler 更准确。主线程 GC 会怎样?
可能 STW 导致掉帧,列表滑动卡顿常与分配+GC 相关。
#6 OOM 有哪些常见类型? 🔥
标准回答
Java 层常见:OutOfMemoryError: Java heap space(堆满)、Failed to allocate a Bitmap(大图)、pthread_create failed(线程过多)等;还有Metaspace(热加载类过多)。Native OOM 来自 SO/Bitmap 像素不在 Java 堆。
面试官可能继续追问
Android 里 OOM 怎么排查?
先分清 Java heap、Native、线程栈哪一类,再对症优化;onTrimMemory系统低压时应释放缓存。OOM 一定因为泄漏吗?
不一定,也可能是正当峰值(大图列表)或缓存过大。onTrimMemory有什么用?
系统低压时回调,应释放缓存、降采样图片,延缓 OOM。
#7StackOverflowError和 OOM 有什么区别? ⭐
标准回答
StackOverflowError是虚拟机栈深度超限,常见无限递归;OutOfMemoryError是堆/元空间/Native 等分配失败。
面试官可能继续追问
Android 里两者怎么区分?
业务中栈溢出较少见,OOM 更常见。自定义 View 的onMeasure互调、深度嵌套 Compose 组合若写错也可能栈溢出。能 catch OOM 吗?
理论上可 catchError,但状态已不可靠,应预防而非依赖捕获。线程栈大小能调吗?
可-Xss,但 Android 应用一般不手调,优先减线程数。
#8 方法区 / 元空间存什么?Android 里怎么理解? ⭐
标准回答
存类元数据:类型信息、常量池、静态变量、JIT 代码等。JDK 8 后用元空间(本地内存)取代永久代。ART 同样有运行时元数据区,但应用开发者少直接调。
面试官可能继续追问
Android 里方法区相关泄漏?
更常遇到的是静态变量持有 Context导致堆泄漏,而非元空间 OOM。常量池和字符串池关系?
字符串字面量在堆中运行时常量池管理,intern 行为面试知道即可。静态变量存在哪?
引用在方法区/元数据逻辑区,所指对象仍在堆。
进阶层(7 题)
#9 常见 GC 算法有哪些? ⭐
标准回答
标记-清除:产生碎片;复制:新生代常用,空间换时间;标记-整理:减少碎片,老年代常见。ART 采用并发/分代等组合策略,与 HotSpot G1/ZGC 不完全相同。
面试官可能继续追问
Android 面试 GC 算法怎么答?
答清思想即可,重点转「如何少产生垃圾、避免泄漏」。什么是 STW?
Stop-The-World,GC 时暂停应用线程,停顿时间是优化指标。标记阶段如何找垃圾?
从 GC Roots 可达性遍历,不可达即垃圾。
#10 ART 的 GC 和 JVM HotSpot 有什么差异? ⭐
标准回答
ART 为移动端优化:安装时 AOT、运行期 JIT、多种并发 GC(随版本演进)。更关注停顿时间与电池。
面试官可能继续追问
Android 开发者需要背 ART GC 细节吗?
不必背源码,应会说:「移动端忌频繁分配与长停顿,用 Profiler 看分配链,用 LeakCanary 看泄漏。」Dalvik 和 ART 差别还要答吗?
知道 ART 取代 Dalvik、GC 与编译策略更现代即可,别展开过时细节。为什么列表滑动要优化分配?
滑动路径频繁分配触发 GC,与 ART 停顿叠加造成 jank。
#11 内存泄漏和内存溢出有什么区别? 🔥
标准回答
泄漏:不再使用的对象仍被 GC Roots 引用链持有,占堆不释放,最终可能引发 OOM。溢出:需要的内存在某时刻超过可用上限,不一定有泄漏(如一次加载超大图)。
面试官可能继续追问
Android 经典内存泄漏场景?
静态Context、Handler 非静态内部类持 Activity 且延迟消息未清、监听未注销、单例持Activity。泄漏一定会 OOM 吗?
不一定立刻,但泄漏累积或配合峰值会触发。怎么快速判断是泄漏还是峰值?
重复操作后内存曲线是否只升不降,配合 heap dump 看 Dominator。
#12 Android 内存泄漏排查的一般流程? 🔥
标准回答
1)Profiler Memory 看曲线是否泄漏型增长;2)重复进入退出页面强制 GC 后仍不降则可疑;3)Export heap dump;4)MAT/Analyzer 找 Dominator Tree 大对象与 GC Root 路径;5)对照代码断引用链。
面试官可能继续追问
Android 泄漏排查工具链?
线上结合 LeakCanary、Bugly 内存告警;排查时把 Handler 泄漏、静态 Context 等经典场景串起来讲。为什么强制 GC 后仍占内存不一定是泄漏?
缓存、图片池等正当持有会保留,要看业务是否合理。主线程能做 dump 吗?
大堆 dump 会卡,宜后台或测试包操作。
#13 LeakCanary 的原理是什么? 🔥
标准回答
监控Activity/Fragment销毁后是否仍被引用:弱引用 + 引用队列,若 GC 后未入队则说明泄漏;结合 Shark 库分析引用链并通知开发者。
面试官可能继续追问
Android 里 LeakCanary 怎么用?
debug 集成 LeakCanary,release 用轻量上报。原理本质是可达性 + 延迟确认,不是魔法抓所有 Native 泄漏。LeakCanary 能抓 Native 泄漏吗?
主要抓 Java/Kotlin 堆引用链,Native 需 Profiler Native 轨或专用工具。为什么用弱引用?
不阻止 Activity 被正常回收,只观察是否应死仍活。
#14 Bitmap 为什么容易导致 OOM? 🔥
标准回答
像素缓冲区可达「宽×高×4 字节」,一张 4K 图就数十 MB;列表多张叠加极易爆堆或 Native。解码默认ARGB_8888,未采样、未复用都会放大问题。
面试官可能继续追问
Android 里 Bitmap 怎么防 OOM?
应用inSampleSize、硬件位图、BitmapPool(Glide)、RGB_565降质等手段。Bitmap 内存算 Java 堆还是 Native?
版本与配置有关,历史上部分在 Native;OOM 日志需分类型看。Glide 为什么比手写解码安全?
自动采样、生命周期绑定位图请求、内存与磁盘缓存策略成熟。
#15 Android Studio Profiler 的 Memory 面板怎么看? ⭐
标准回答
看实时 Java/Native 占用曲线、分配对象数与分配调用栈(Record allocations)。操作路径:压测场景 → Record → 强制 GC → 观察曲线是否回落 → 抓 dump 分析类实例数。
面试官可能继续追问
Android Studio Profiler Memory 怎么看?
列表滑动卡顿常配合 Allocation 看是否在onBindViewHolder里疯狂new;与 CPU、Energy 面板联合判断。分配记录开销大吗?
有开销,仅调试短时间开启。如何看是哪个类泄漏?
dump 后按 Retained Size 排序,查异常多的Activity/Fragment实例。
核心层(7 题)
#16 强软弱虚引用分别是什么?用在哪? 💡
标准回答
强引用:默认new,不回收。软引用:内存紧张前可回收,适合缓存。弱引用:下次 GC 即回收,WeakHashMap/LeakCanary。虚引用:跟踪对象回收时机,堆外清理辅助。
面试官可能继续追问
Android 里引用类型怎么用?
应用缓存可用LruCache(强引用+淘汰),避免全局软引用不可控;理解弱引用才能讲清泄漏检测。软引用当缓存靠谱吗?
回收时机不可控,现代工程更倾向 LruCache + 明确上限。WeakHashMap 键没了值还在吗?
键弱引用被回收后,条目会在下次 GC 清理。
#17 GC Roots 有哪些? 💡
标准回答
可达性分析起点:虚拟机栈中引用的对象、方法区静态属性、常量引用、JNI 引用、活跃线程等。泄漏分析本质是找本不应再可达却仍从 Root 到达的路径。
面试官可能继续追问
Android 泄漏分析怎么用 GC Roots?
如静态字段 → 单例 → 已销毁Activity;MAT 的「Path to GC Roots」是面试高频操作题。局部变量算 GC Root 吗?
栈帧里的引用是 Roots 的一部分,方法未结束对象就死不了。匿名内部类为什么易泄漏?
隐式持有外部类引用,形成 Root 链到 Activity。
#18 分代收集的思想是什么? 💡
标准回答
大部分对象朝生夕死,新生代用复制 GC 频繁清理;存活久的进老年代,回收更少但更重。分代假设提高整体效率。ART 有类似分代/区域策略(随版本演进)。
面试官可能继续追问
Android 开发理解分代有什么用?
短生命周期对象别误被长生命周期容器持有,否则「晋升」老年代加大 Full GC 成本。对象什么时候进老年代?
年龄阈值、大对象直接进老年代等,知道概念即可。缓存放太多会怎样?
长生命周期对象多,老年代膨胀,GC 停顿变长。
#19 heap dump 分析的具体步骤? ⭐
标准回答
导出 hprof → Android Studio/MAT 打开 → 按 Retained Heap 排序 → 找异常多实例 → Path to GC Roots 排除弱/软引用 → 定位字段引用 → 改代码断链。
面试官可能继续追问
Android heap dump 注意什么?
注意混淆包名用 mapping 还原;线上大堆 dump 注意隐私与体积。Shallow 和 Retained 区别?
Shallow 对象自身大小;Retained 含其独占可达子树,排泄漏看 Retained。hprof 太大怎么办?
缩短复现路径、过滤包名、分场景多次 dump。
#20android:largeHeap能解决内存问题吗? ⭐
标准回答
largeHeap=true仅申请更大堆上限,不修复泄漏也不优化分配,部分机型有效、行为不一致,Google 不推荐依赖。
面试官可能继续追问
Android 里
largeHeap能用吗?
治标不治本,不能当长期方案;正确做法是修泄漏、图片采样、控缓存、响应onTrimMemory。怎么查看应用堆上限?
ActivityManager.getMemoryClass()/getLargeMemoryClass()。不同厂商堆上限一样吗?
不一样,低端机更紧,必须在真机压测。
#21 Android 内存优化有哪些工程实践? 🔥
标准回答
少分配:对象池、复用ViewHolder、避免在 draw/layout 里new。控生命周期:弱引用、及时注销监听、协程随viewModelScope取消。图片:采样、webp、Glide 策略。缓存:有界 LruCache,系统低压释放。
面试官可能继续追问
Android 内存优化工具链?
LeakCanary、Profiler、线上 APM;Handler 泄漏、大图与线程过多等场景一并纳入优化清单。Compose 有何特别注意?
重组过多分配会加重 GC,稳定remember、减少不稳定 lambda。Room 大查询会 OOM 吗?
一次加载超大 Cursor 会,应分页或 Paging。
#22 Finalizer 和 Cleaner 还有必要了解吗? 💡
标准回答
Object.finalize()已废弃(JDK 9+),回收时机不确定且可能复活对象,不应依赖。Cleaner/PhantomReference用于堆外资源回收辅助,如 DirectByteBuffer。工程上资源释放应在close()/onDestroy显式完成,别赌 Finalizer。
面试官可能继续追问
Android 里资源释放怎么做?
Kotlinuse和 try-with-resources 自动close(),IO/游标场景首选,防泄漏。为什么 finalize 会导致性能问题?
对象需多轮 GC 才能进 F-queue,拖慢回收。Kotlin
use和 try-with-resources?
自动close(),IO/游标场景首选,防泄漏。
面试策略速查
| 面试等级 | 建议掌握 |
|---|---|
| 初级 | ★★★☆☆ |
| 中级 | ★★★★★ |
| 高级 | ★★★★★ |
必背知识(🔥)
堆栈分区、Minor/Full GC、OOM 类型、泄漏 vs 溢出、泄漏排查流程、LeakCanary、Bitmap OOM、内存优化实践
高频追问
「泄漏和溢出区别」「Bitmap 怎么省内存」「largeHeap 能用吗」「如何看 GC Root 路径」
加分项(💡)
强软弱虚引用、GC Roots 清单、分代思想、Finalizer 废弃原因、Shallow vs Retained
容易踩坑
把 largeHeap 当万能药;忽略 Native OOM;不会用 dump 只会背算法名;混淆 StackOverflow 与 OOM;依赖System.gc()
完整链路一句通
内存题一条线:对象在堆、引用在栈,用完须断 GC Root 链防泄漏;分配过多或大图触发 GC 停顿与 OOM;用 Profiler 看曲线与分配栈,dump 后沿 GC Roots 找持有者,图片采样与有界缓存是日常优化主战场。
相关推荐
Android 高级工程师面试:Java 基础知识 近1年高频追问 22 题
Android 高级工程师面试:Java 多线程与并发 近1年高频追问 22 题