字节跳动 Java 社招面经:JIT、垃圾回收与堆外内存
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- JIT 编译器怎样工作,分层编译如何平衡启动与运行性能?
- CMS 与 G1 的主要差异是什么,垃圾收集器如何选择?
- 日志显示 GC 停顿只有 10 毫秒,但服务卡顿 10 秒,如何排查?
- HashMap 为什么需要树化与退化,两种转换的阈值有什么区别?
- 怎样等待多个并发任务完成,CountDownLatch、CyclicBarrier 和 CompletableFuture 如何选择?
- 你主导过什么复杂架构决策,怎样验证迁移与回滚方案?
- 直接内存或其他堆外内存持续增长时如何定位?
- ZGC 如何把大部分回收工作与应用线程并发执行?
《参考解析》
短 GC 与长卡顿
先把 GC 日志、请求延迟、线程池队列和下游耗时放到同一时间线上。短暂的暂停可能触发积压,但也可能只是与网络重试、锁竞争或 CPU 饥饿同时发生。要找到十秒花在哪个阶段,不能看到一次 GC 就推定它造成了全部延迟。
JIT 的收益与边界
热点代码编译为机器码后,编译器可以做内联、消除无用计算和标量替换;这些优化依赖运行时观察,假设不成立时可能去优化。逃逸分析并不意味着所有未逃逸对象都会按字面直接放在栈上,回答时应把分析结论和具体优化区分开。
堆外排查
先比较进程常驻内存、Java 堆、直接缓冲区和线程数量的趋势。启用相应诊断后,NMT 可帮助拆分 JVM 自身的原生内存类别,但不能把它当作覆盖所有第三方本地分配的工具。直接缓冲区的释放还与 Java 引用和清理机制有关,不能简单说堆外内存完全不受垃圾回收影响。
HashMap 转换
树化和退化有不同条件,还要考虑数组容量;不是链表一长就必然树化。原帖题干把红黑树转链表与阈值 8 混在一起,作答前先澄清讨论的是哪个方向,再结合目标 JDK 的实现解释。