岗位索引

后端开发工程师面试题库第 2 页

后端开发面试题解析,覆盖缓存、数据库、分布式和系统设计基础。

378 道题 15 个公司 134 个知识点

后端开发相关面试题第 2 页

CLOSE_WAIT 和 TIME_WAIT 分别是什么?

CLOSE_WAIT 和 TIME_WAIT 都是 TCP 连接关闭过程中的状态,但含义完全不同。CLOSE_WAIT 出现在被动关闭方,表示对端已经发来 FIN,本端已经确认,但应用还没有调用 close 结束连接;TIME_WAIT 出现在主动关闭方,表示本端完成主动关闭后仍保留连接一段时间,用于处理延迟报文和保证对端收到最后的 ACK。

netty有哪些组件?

Netty 的组件可以按启动配置、连接抽象、线程模型、事件流转、数据缓冲、编解码、业务处理、异步通知来理解。回答时不应只罗列类名,而要把 ServerBootstrap 启动服务端、EventLoopGroup 分配线程、Channel 承载连接、Pipeline 串联 Handler、ByteBuf 承载数据、Future 返回异步结果这条链路讲清楚。

常见 JVM 垃圾收集器分别适合什么场景?

垃圾回收器适用场景不能只背名称,而要围绕吞吐量、停顿时间、堆大小、对象生命周期、CPU 余量和运行时版本来选择。Serial 适合小堆和低资源环境,Parallel 适合吞吐优先任务,CMS 是旧版本低停顿方案但有碎片和并发失败风险,G1 是较新主流服务端的平衡型选择,ZGC 与 Shenandoah 面向更严苛的低停顿和大堆场景,Epsilon 只适合测试、压测和短生命周期实验。

什么情况服务器会有大量的TIME_WAIT连接?

服务器出现大量 TIME_WAIT,本质上说明这台机器在大量 TCP 连接中充当了主动关闭方,并且连接关闭后需要保留 2MSL 时间以保证最后一个 ACK 可重传、旧报文不会污染后续连接。常见诱因包括短连接比例高、高并发请求快速结束、服务端主动断开 HTTP 连接、未开启或未复用 keep-alive、反向代理到后端使用短连接、客户端或上游连接池配置不合理,以及瞬时流量尖峰。大量 TIME_WAIT 本身不一定是故障,但如果伴随本地端口耗尽、连接建立失败、CPU 软中断升高或 accept/connect 异常,就需要结合业务关闭方向、连接复用、系统参数和网络路径做定位。

进程通信方式分别适合什么场景?

这道题考察的不是背诵 IPC 名词,而是能否根据进程关系、通信方向、数据量、时延、可靠性、同步需求和部署范围选择合适方案。回答时应先按场景分类:父子进程简单字节流用管道,本机无亲缘进程可用 FIFO、消息队列或本地 Socket,高吞吐大块数据用共享内存配合同步原语,事件通知用信号,跨主机通信用网络 Socket,文件或 mmap 适合持久化、低频共享和大文件映射。

JVM 堆内存通常如何分区?

JVM 堆可以从两条线理解:按对象生命周期分为年轻代和老年代,年轻代内部又分 Eden 和两个 Survivor;按具体垃圾收集器实现,传统分代收集器更强调连续代空间,G1、ZGC、Shenandoah 等更强调 region 或分区化管理。回答时要特别说明:元空间和线程栈不属于堆,TLAB 是 Eden 中给线程预分配的私有分配缓冲区,大对象可能直接进入老年代或被特殊 region 管理。

堆上的元素满了会发生什么?

JVM 堆满通常指堆内存中可用于对象分配的空间不足。对象分配失败后,虚拟机会先尝试触发 Young GC 或 Full GC 回收空间;如果回收后仍无法满足分配,或者老年代晋升失败、连续 GC 效率过低,就可能抛出 OutOfMemoryError。回答时要围绕对象分配、GC 尝试、晋升失败、OOM 类型、排查与预防展开,不要误讲成优先队列里的堆元素满了。

数组和链表有什么区别?

数组和链表都是线性表,但底层组织方式不同:数组用连续内存存放元素,链表用离散节点通过引用连接。这个差异决定了数组随机访问快、缓存友好,但插入删除和扩容成本可能高;链表插入删除在已定位节点时很快,但查找慢、缓存局部性差、额外指针开销大。工程上不能只背复杂度,要说明复杂度成立的前提,并结合 Java 的 ArrayList 和 LinkedList 对照。

同题还出现在 1 个公司岗位

红黑树和平衡二叉树的区别?

红黑树和平衡二叉树都是为了避免普通二叉搜索树退化成链表而设计的自平衡二叉搜索树,核心区别在于平衡标准和维护成本。面试中说的平衡二叉树通常特指 AVL 树:它要求每个节点左右子树高度差最多为 1,平衡非常严格,所以查询路径更短;红黑树用颜色规则约束黑色节点数量和红色节点相邻关系,允许一定程度的不完全平衡,因此插入、删除时旋转和调整更少,更适合频繁更新的工程场景。

cpp的虚函数以及实现原理?

虚函数是 C++ 实现运行时多态的核心机制。它允许通过基类指针或引用调用派生类重写后的函数,把调用哪个函数的决定从编译期推迟到运行期。主流编译器通常通过虚函数表和对象中的虚表指针实现:多态类有虚表,对象保存指向虚表的指针,虚调用时先取虚表指针,再按固定槽位找到函数地址并间接调用。

C++多态怎么实现?

C++ 多态本质上是同一接口在不同类型上表现出不同行为。它分为编译期多态和运行期多态:编译期多态由函数重载、运算符重载、模板等在编译阶段完成选择;运行期多态依赖 virtual 虚函数、继承、重写以及基类指针或引用,在程序运行时根据对象真实类型进行动态绑定。回答不能只停留在虚函数表四个字,还要讲清楚触发条件、对象内存模型、构造析构规则、虚析构必要性、对象切片和多继承下的边界问题。

Redis的List底层实现原理?

Redis List 的底层实现经历过从 ziplist 与 linkedlist 的组合,到 quicklist 统一承载的演进。核心目标不是单纯追求某一种操作最快,而是在两端插入删除、内存占用、缓存友好性和中间位置修改之间做平衡。回答时要讲清:List 是有序、可重复、按插入顺序组织的线性结构,适合队列、栈、简单消息流等场景,但索引访问和中间元素定位不是它的强项。

为什么要用redis?

Redis 的核心价值不是更快的数据库,而是把高频、低延迟、可短期容忍一致性差异的数据放到内存侧处理,从而缩短读写链路、削峰填谷、降低关系型数据库压力,并利用丰富数据结构、原子命令、过期机制和高可用能力支撑缓存、计数、排行榜、限流、会话、队列等典型场景。

Redis 缓存淘汰策略有哪些?

这题要先区分两个概念:过期删除是针对设置了 TTL 的键,缓存淘汰是 Redis 在内存达到 maxmemory 限制后,为了腾出空间而选择删除哪些键。回答时不能只背策略名称,还要说明 allkeys 与 volatile 的区别、LRU/LFU/TTL/random/noeviction 的选择逻辑,以及这些策略在读多写多、冷热数据明显、TTL 管理严格等场景下的取舍。

Redis 为什么高可用?

Redis 的高可用不是单一能力,而是复制、故障检测、自动切换、分片容灾、持久化、客户端重连和监控治理共同组成的体系。主从复制提升读扩展和副本冗余,哨兵负责发现主节点故障并自动完成主从切换,Cluster 通过分片和多主多从避免单机容量与单点问题,AOF/RDB 持久化降低进程或机器故障后的数据损失。真正回答这道题时,要同时说明 Redis 能恢复服务、能减少数据丢失,但不能承诺在所有极端场景下零丢失,尤其要讲清复制延迟、脑裂和一致性取舍。