面灵AI

字节跳动 Java 社招面经:JIT、垃圾回收与堆外内存

时间
2026-09
来源
牛客网

《面试题目》

  1. JIT 编译器怎样工作,分层编译如何平衡启动与运行性能?
  2. CMS 与 G1 的主要差异是什么,垃圾收集器如何选择?
  3. 日志显示 GC 停顿只有 10 毫秒,但服务卡顿 10 秒,如何排查?
  4. HashMap 为什么需要树化与退化,两种转换的阈值有什么区别?
  5. 怎样等待多个并发任务完成,CountDownLatch、CyclicBarrier 和 CompletableFuture 如何选择?
  6. 你主导过什么复杂架构决策,怎样验证迁移与回滚方案?
  7. 直接内存或其他堆外内存持续增长时如何定位?
  8. ZGC 如何把大部分回收工作与应用线程并发执行?

《参考解析》

短 GC 与长卡顿

先把 GC 日志、请求延迟、线程池队列和下游耗时放到同一时间线上。短暂的暂停可能触发积压,但也可能只是与网络重试、锁竞争或 CPU 饥饿同时发生。要找到十秒花在哪个阶段,不能看到一次 GC 就推定它造成了全部延迟。

JIT 的收益与边界

热点代码编译为机器码后,编译器可以做内联、消除无用计算和标量替换;这些优化依赖运行时观察,假设不成立时可能去优化。逃逸分析并不意味着所有未逃逸对象都会按字面直接放在栈上,回答时应把分析结论和具体优化区分开。

堆外排查

先比较进程常驻内存、Java 堆、直接缓冲区和线程数量的趋势。启用相应诊断后,NMT 可帮助拆分 JVM 自身的原生内存类别,但不能把它当作覆盖所有第三方本地分配的工具。直接缓冲区的释放还与 Java 引用和清理机制有关,不能简单说堆外内存完全不受垃圾回收影响。

HashMap 转换

树化和退化有不同条件,还要考虑数组容量;不是链表一长就必然树化。原帖题干把红黑树转链表与阈值 8 混在一起,作答前先澄清讨论的是哪个方向,再结合目标 JDK 的实现解释。