news 2026/9/30 8:03:27

大数据面试高频考点:SQL窗口函数、Spark原理与数仓建模全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大数据面试高频考点:SQL窗口函数、Spark原理与数仓建模全解析

1. 大数据面试到底在考什么——先把这个搞清楚再刷题

说实话,我在这个圈子里混了十几年,面过的人少说也有几百个,自己也换过几次工作。我观察到的最普遍现象是:很多候选人刷题的方式完全跑偏了。有的人抱着LeetCode死磕hard题,有的人把时间全花在背八股文上,结果一到手写SQL或者聊项目细节就露馅。

大数据岗位的笔试题和纯后端开发不一样。面试官想考察的东西其实非常集中:SQL能力是绝对的底线,分布式计算的原理是分水岭,框架源码是加分项,数据建模能力决定了你能不能干高级活。这篇文章我会结合真实面试中出现频率最高的题目,把每个模块的核心考点、解题思路、以及我自己总结的避坑经验全部拆开讲。

先给一个整体图谱,大数据笔试题基本逃不出这几个方向:

  • SQL:窗口函数、行转列列转行、留存率计算、连续登录问题、TopN问题
  • Java:集合源码、并发编程、JVM基础(大数据岗考得比后端浅,但集合和并发必考)
  • HDFS/YARN:读写流程、架构设计思想、容错机制
  • MapReduce:Shuffle机制、数据倾斜、Join策略
  • Spark:RDD/DataSet/DataFrame区别、宽窄依赖、Stage划分、调优、数据倾斜、Shuffle
  • Flink:状态管理、Checkpoint机制、窗口、精确一次性语义、背压
  • 数仓:分层架构、维度建模、拉链表、缓慢变化维、事实表分类

一句话总结:SQL决定你能不能过笔试,框架原理决定你能不能过技术面,数仓和调优决定你能拿什么级别的offer。下面我按模块逐个拆解。

2. SQL笔试题——大数据岗的命根子

2.1 窗口函数:必考中的必考

不管你是面数仓岗、数据开发岗还是数据工程师,SQL笔试第一题大概率是窗口函数。我甚至见过有些公司笔试题全部都是窗口函数,搞了8道题全是rank、row_number、lag、lead的组合应用。

窗口函数的本质就是在每一行上打开一个“窗口”,在这个窗口范围内做计算。关键要分清over子句里的三个部分:partition by决定窗口怎么切分,order by决定窗口内怎么排序,rows/range between决定窗口的边界范围。

高频考点主要有这几类:

排名类:rank()、dense_rank()、row_number()三兄弟的区别,这个几乎是必问的。rank是跳跃排名,比如两个人并列第一,那第三名直接是3;dense_rank是连续排名,并列第一后第二名是2;row_number是纯行号,即使值一样也会强制分出先后。真实场景里,取每个分组的前N条记录,99%用的是row_number。

前后行取值类:lag()和lead()。计算环比、同比、会话时长、用户行为序列分析全靠这两个函数。lag是取上一行,lead是取下一行,第三个参数是默认值。

聚合类:sum()、avg()、count()配合over,这类题通常用于计算累计值。累计求和是经典题,要注意order by的排序字段如果存在重复值,结果可能和预期不一样,这个细节下面单独说。

窗口边界类:rows between unbounded preceding and current row是累计到当前行,rows between 1 preceding and 1 current row是算移动平均。这类题在金融领域出现得很频繁。

我在面试中经常问的一道经典题是:统计每个用户连续登录天数。这题的精髓不在于窗口函数本身,而在于用row_number生成序号后,用登录日期减去序号得到“分组标识”,差相同的行属于同一个连续区间。具体做法:

select user_id, group_id, count(*) as 连续天数 from ( select user_id, log_date, date_sub(log_date, row_number() over(partition by user_id order by log_date)) as group_id from user_login_log where log_date between '2025-01-01' and '2025-01-31' ) t group by user_id, group_id

这个思路必须刻在脑子里。连续天数、连续签到、连续消费、连续活跃,本质上都是这个套路。

2.2 行转列与列转行:SQL笔试的经典款

行转列通常用case when配合聚合函数实现。举个最常见的例子:统计每个用户在不同渠道的消费金额,输出格式是一行一个用户,每个渠道是一列。

select user_id, sum(case when channel = 'app' then amount else 0 end) as app_amount, sum(case when channel = 'web' then amount else 0 end) as web_amount, sum(case when channel = 'mini_program' then amount else 0 end) as mini_amount from user_pay_records group by user_id;

为什么用sum而不是max?因为同一个用户同一个渠道可能有多条记录,如果用max会丢失数据,用sum才能保证金额累加正确。这个细节很多人会踩坑。

列转行用的是union all或者lateral view explode。Hive/Spark SQL里用explode配合lateral view,纯SQL或者MySQL里用union all硬拼。列转行在实际业务中出现的频率也很高,比如把一行里的多个属性拆成多行做明细分析。

2.3 留存率计算:面试官最爱考的指标题

留存率几乎是数仓岗笔试的必考大题。留存率的难点在于理解时间窗口的概念——留存N日,是指某个时间点新增的用户,在N天后仍然活跃的比例。

以计算7日留存为例,思路如下:

  • 先圈出所有在某个时间窗口新增的用户,记录其首日活跃日期
  • 然后关联这波用户在后续每一天的活跃记录
  • 用第7天的活跃人数除以首日新增人数,得到7日留存率
with new_users as ( select user_id, min(active_date) as first_active_date from user_active_log group by user_id ), active_log as ( select user_id, active_date from user_active_log where active_date >= '2025-01-01' ) select n.first_active_date as 新增日期, count(distinct n.user_id) as 新增用户数, count(distinct case when datediff(a.active_date, n.first_active_date) = 6 then a.user_id end) as 第七日活跃人数, count(distinct case when datediff(a.active_date, n.first_active_date) = 6 then a.user_id end) / count(distinct n.user_id) as 七日留存率 from new_users n left join active_log a on n.user_id = a.user_id group by n.first_active_date;

注意几个容易出错的地方:新增用户表要先去重,活跃日志表要过滤时间范围,关联时用left join保证没有活跃记录的用户不会丢失,留存率的计算要用distinct避免同一用户重复计数。

2.4 如何提升SQL笔试的通过率

我在真实笔试中总结出的经验:SQL题答得好不好,和刷题量有关系,但和思路的清晰度关系更大。看到题目先花30秒思考“有几张表、数据粒度是什么、最终输出需要什么粒度”,比着急忙慌写代码重要得多。

提高准确率的具体建议:

  • 所有的表先看主键,搞清楚一张表的粒度,用户表是一行一个用户,订单表是一行一个订单,明细表是一行一个行为
  • 写完SQL后用“脑内测试”法,构造两三行假数据,手动跑一遍逻辑,看输出是否符合预期
  • 注意null的处理,count(字段)不会统计null,count(*)会,这个区别可以救你一命
  • join之前先确认关联键是否唯一,一对多join会产生笛卡尔积导致数据膨胀,这个bug非常隐蔽

另外强烈建议每个准备面试的人把牛客SQL题库刷两遍,第一遍按顺序做,第二遍按题型刷。尤其是困难难度那一档,里面的非等值join、自连接、嵌套子查询思路,面试中真的会出现类似的。

3. 大数据核心组件原理——从Hadoop到Spark的必背清单

3.1 HDFS和YARN的高频题

HDFS常考的点集中在读写流程和设计思想上。读写流程要能画出来、讲清楚每个环节的通信过程,面试官会追问细节,比如写数据时DataNode宕机了怎么办、副本因子怎么确定、机架感知的作用是什么。

HDFS写流程的要点是客户端先向NameNode请求上传,NameNode返回允许写入的DataNode列表,然后客户端把数据按块写入第一个DataNode,再由第一个DataNode以管道方式复制到第二、第三个DataNode。每写一个chunk就会通过Packet逐级反馈ack,全部完成后客户端通知NameNode关闭文件。

这个流程里有一个很容易被问到但大多数人答不出来的点:为什么管道复制是“增量式”的?因为客户端每写入一个chunk的数据,就会立刻传给下一个DataNode,同时自己也继续读下一个chunk,这样网络传输和磁盘写入是重叠进行的,吞吐量最优。如果等一个块全部写完了再复制,效率会低一个数量级。

HDFS为什么不适合存大量小文件?因为NameNode把元数据存在内存里,一个文件、一个目录、一个block都要占用约150字节的元数据空间。一亿个小文件会直接吃掉几个GB的内存,而且读文件时需要频繁访问NameNode获取元数据,瓶颈非常明显。解决办法是使用SequenceFile、ORC、Parquet等格式合并小文件,或者用Hive的Concatenate、Spark的coalesce/repartition来归并。

YARN的核心考点是ResourceManager的调度机制和Container的生命周期。理解YARN的关键在于区分“资源申请”和“任务执行”这两个流程。ApplicationMaster向ResourceManager申请资源,拿到Container后启动Task,任务结束后ApplicationMaster注销并释放资源。面试如果问到Spark on YARN的两种模式——client和cluster的区别,本质区别在于Driver跑在哪里,以及由谁负责申请资源。

3.2 MapReduce的必考点:Shuffle和数据倾斜

MapReduce虽然在实际生产中越来越少直接写,但它的Shuffle机制是整个分布式计算的基础,面试必考。Shuffle就是把Map的输出按key分区、排序、合并后传输给Reduce的过程。

完整流程:Map端输出后先写入内存缓冲区(默认100MB),达到阈值后溢写磁盘;溢写过程中做分区、排序、combiner(可选);然后Merge多个溢写文件形成一个大的混合文件,同时做归并排序。Reduce端通过fetcher拉取属于自己的那部分数据,然后做合并排序,最后交给reduce函数处理。

面试追问点通常是这几个:

  • 为什么需要combiner?它的本质是局部聚合,在Map端先做一次reduce操作,减少跨节点传输的数据量。combiner必须满足一个条件:输入和输出的类型与reduce函数一致,且多次应用combiner的结果与一次应用reduce一致。因为combiner涉及函数的幂等性,不是所有reduce逻辑都能直接用combiner,比如求平均值的reduce就不能直接做combiner
  • 为什么溢写前要做排序?因为最终各节点数据需要合并成有序序列,Map端先排序可以减轻Reduce端的排序压力,整体效率更高
  • 数据倾斜的本质是某些key的数据量远大于其他key,导致单个Reduce节点负载极高。缓解手段:增加Reduce数量(治标不治本)、对key加随机前缀打散(适合聚合类任务,需要两阶段聚合)、自定义Partitioner(适合关联键分布极度不均的情况)

3.3 Spark Core的高频题:RDD、依赖关系与Stage划分

Spark面试题比Hadoop更多,题量大、层次深。从基础概念到源码级追问都有可能,我遇到过从“什么是RDD”一路问到“DAGScheduler怎么切分Stage”的连环炮式追问。

RDD、DataFrame、DataSet的区别这道题,很多人的回答是“RDD是弹性分布式数据集,DataFrame有schema,DataSet强类型”,但面试官想要的是一套能说明演进逻辑的回答。更好的答题框架是:

  • RDD是Spark 1.0时代的核心抽象,提供了函数式编程接口,缺点是Java/Scala类型安全差、缺乏自动优化、序列化开销大
  • DataFrame在RDD之上引入了schema信息,让Spark能通过Catalyst优化器做逻辑优化和物理优化,性能大幅提升,缺点是类型不安全,编译期不报错,运行期才发现
  • DataSet结合了两者优点,既有类型安全,又能利用优化器,但在实际开发中,如果使用Spark SQL做数据加工,直接操作DataFrame就够了,写自定义UDF、UDAF时才更需要DataSet的类型安全

宽窄依赖和Stage划分是Spark面试的绝对核心。窄依赖指父RDD的每个分区最多被子RDD的一个分区使用,常见算子包括map、filter、union、coalesce;宽依赖指父RDD的每个分区被子RDD的多个分区使用,常见算子包括groupByKey、reduceByKey、join。宽依赖意味着Shuffle,Shuffle会产生磁盘IO和网络传输,是Spark性能瓶颈的主要来源。

Stage的划分规则是:从后往前遇到宽依赖就切断,生成一个新的Stage。DAGScheduler根据RDD的依赖关系构建DAG,然后反向拓扑排序,把stage切出来。每个Stage内部都是窄依赖算子串联,可以流水线执行。面试官通常还会追问一句:为什么窄依赖可以流水线执行?因为窄依赖下父分区和子分区一一对应,数据不需要跨节点传输,可以直接在同一个Executor上连续执行多个算子。

Spark数据倾斜是面试必问,也会在系统设计题中出现。常见的倾斜表现是某个Stage卡住不动,Spark UI上看某个Task处理的数据量明显偏大,或OOM。解决思路按优先级排序:

  • 过滤掉导致倾斜的异常key(脏数据)
  • 提高Shuffle并行度,让每个Task处理的数据量变少
  • 两阶段聚合:先加随机前缀将key打散,做第一轮局部聚合,去掉前缀再做第二轮聚合
  • 对倾斜的key单独处理:把倾斜的key筛出来走广播Join,不倾斜的key走普通Join
  • 使用广播变量替代shuffle join,适用于小表关联大表的场景

3.4 Flink的高频题:状态、Checkpoint与精确一次

Flink在笔试题中的比重逐年增加,尤其是实时数仓岗位。常考的点集中在状态管理、Checkpoint机制、窗口操作、背压四个方面。

状态管理主要考状态类型分类:Keyed State和Operator State。Keyed State又分为ValueState、ListState、MapState、ReducingState、AggregatingState。要能说清楚状态存储后端:MemoryStateBackend(存TaskManager堆内存,适合小状态)、FsStateBackend(状态存堆内、Checkpoint存文件系统)、RocksDBStateBackend(本地RocksDB存储,适合超大状态)。在真实生产环境中,超大状态几乎必选RocksDB。

Checkpoint机制的核心是Barrier对齐。Source端周期性地向数据流中插入Barrier,每个算子收到Barrier后做状态快照,多输入流的算子需要等待所有输入流的Barrier对齐后才能快照。面试追问通常集中在“Barrier不对齐怎么办”和“状态和外部系统的一致性怎么保证”这两个问题上。

精确一次语义(Exactly Once)的实现机制:Source端记录消费偏移量,Sink端使用两阶段提交协议,Checkpoint完成时触发预提交和正式提交。如果事务提交失败,整个作业会回滚到上一个Checkpoint状态。Kafka + Flink端到端精确一次的经典组合是:Kafka作为Source记录offset,Kafka/S3等支持事务的Sink配合TwoPhaseCommitSinkFunction实现。

背压是另一个高频问题。Flink背压的核心机制是TaskManager之间通过netty通信,当下游处理速度慢时,上游发送端的buffer会积压,导致发送速率自然下降。查看背压的方法是Web UI的BackPressure选项卡,或者通过监控指标分析。Flink 1.13之后引入的基于Credit的反压机制能更精细地控制数据发送速率。面试答这道题的思路要落在“背压是系统自动调节机制,不是错误状态”上。

4. 数据仓库与建模题——高阶岗位的分水岭

4.1 数仓分层架构:为什么必须分层

数仓分层这个知识点,笔试和面试都是必考。标准分层是ODS(操作数据存储层)、DWD(明细数据层)、DWS(汇总数据层)、ADS(应用数据层)。有时候中间还会加一层DIM(维度层)和DIM(公共维度层)的变体,但核心思想是一致的。

分层的核心目的绝不是“为了好看”,而是为了控制数据流向和复用。ODS层保持和源系统一致,不做任何加工,本意是保留原始数据用于追溯和重算。DWD层是清洗和规范化后的明细数据,具备业务主题属性,是后续所有表的加工源头。DWS层做轻度汇总,把公共指标预计算好,ADS层面向具体业务需求输出结果。

面试官会问:一张报表要查从ODS到ADS的完整链路,各层分别做了什么?这个问题的意义在于考察你是否真正理解每个层的职责。我常用的回答范例:订单事实数据在ODS层是源系统原样接入的JSON串,DWD层解析成结构化表并统一字段名和枚举值,DWS层按天粒度汇总成订单维度的指标表,ADS层直接查询DWS产出报表。

4.2 维度建模:事实表和维度表的设计原则

维度建模的经典问题是:什么是事实表、什么是维度表、如何区分。事实表记录业务过程和度量值,通常是细粒度、不断增加、不更新的;维度表描述业务过程的上下文环境,通常是缓慢变化、可以更新的。

事实表进一步细分为事务事实表、周期快照事实表、累积快照事实表。面试常问的是它们的使用场景区别:事务事实表记录每笔业务事件(如每笔订单),适合分析业务过程;周期快照事实表按固定频率记录状态(如每天库存余额),适合分析存量状态;累积快照事实表记录业务过程的生命周期(如订单从下单到签收的各阶段时间戳),适合分析流程耗时。

维度建模的另一组高频题是缓慢变化维的处理策略。类型1是直接覆盖,不保留历史;类型2是新增一行并加生效和失效时间,保留完整历史;类型3是增加一列存历史值,保留有限历史。绝大多数业务场景选择类型2,但要明确它的代价是维度表体积膨胀,关联时要带上时间条件才能取到正确的版本。

拉链表是面试手写SQL的常客。拉链表本质是类型2缓慢变化维的简化实现,记录每个key在某个时间区间内的状态。写法上要注意开链和闭链的逻辑:

-- 新增和变更的数据通过union all合并 insert overwrite table dim_user_zip select ... -- 保留未变化的数据 union all select ... -- 新增的数据,start_date = 今天,end_date = 9999-12-31 union all -- 变更的数据:将旧的记录end_date改为昨天 select ..., from dim_user_zip a join (select key, max(start_date) from ... group by key) b where a.key = b.key and a.end_date = '9999-12-31';

这道题的坑在于:一天内同一key可能发生多次变更,需要在update旧记录时确保只更新当前那一条,通常用start_date最大且end_date为9999来定位。

4.3 指标体系设计:从口径到命名规范

数仓岗除了写SQL,还会考指标体系的设计能力。题目通常给一个业务场景(比如电商、网约车、内容平台),让你设计核心指标和维度。重点不在于指标多,而在于口径清晰、层级完整。

以一个电商场景为例,常见考核点:

  • GMV的口径:是支付金额还是下单金额?是否包含退款?未支付订单怎么办?
  • 活跃用户的口径:按设备ID还是用户ID去重?Web端和App端是否打通?
  • 订单转化率的分母:是UV还是访问次数?这个必须在面试现场明确说明

我见过太多候选人在指标口径上栽跟头,根本原因是脑子里没有“需求方在问什么”的意识。回答指标设计题时,先明确指标的业务含义和统计口径,再拆分指标的影响因素(如GMV = UV × 转化率 × 客单价),最后说明指标在数仓中的层级位置(ODS/DWD/DWS/ADS哪一层加工)。这个回答框架基本能覆盖90%的指标设计面试题。

5. 实战策略:如何高效准备大数据笔面试

5.1 根据目标岗位分配优先级

大数据岗位的细分方向差异很大,如果盲目什么都学,效率极低。以我面试过的经验来分类:

数仓开发岗,SQL和数仓建模是绝对核心,权重可能占70%。Hadoop、Spark原理是基础要求,但深度不会特别深。面试官主要确认你能否独立完成从需求分析到模型设计再到SQL开发的全流程。

数据开发/大数据工程师岗,Spark和Hadoop的深度要求更高。SQL也是笔试必考,但侧重点不同。通常会有场景题,让你设计一个离线ETL的完整流程,涉及存储格式选择、分区策略、任务调度、数据质量校验。

实时计算岗,Flink的深度要求极高。从状态后端选型到Checkpoint参数配置到端到端精确一次的实现原理都会考察。SQL考察以窗口函数、双流Join、维表关联为主。

我的建议是先确定目标岗位,再对照上面的优先级分配刷题和复习的时间。不用在低权重内容上死磕,但要保证高权重内容能形成“肌肉记忆”级别的熟练度。

5.2 如何在笔试中稳定发挥

笔试现场和时间赛跑,策略比蛮力更重要。我用过的一个很实用的方法是“时间预算法”:拿到题目先全部扫一遍,预估每道题的难度和用时,按分数权重分配时间。SQL大题如果半小时没想出来,先写一个可运行的初级版本保底,再逐步优化,至少不会交白卷。

另一个非常实用的技巧是“分步验证”:每写完一个query,先用简单的where条件把数据量缩小到肉眼可验证的级别,快速确认逻辑正确性,再放开条件跑全量。笔试环境没有真实数据时,可以用select 'x'来验证语法和运行逻辑是否正确。

答题时注意几个习惯:

  • 命名字段时用易于理解的英文别名,别直接用中文,很多在线笔试系统对中文别名支持不好
  • 能用CTE就用CTE,不要嵌套太多层子查询,一是容易写错,二是理不清逻辑
  • SQL写完检查三个点:表名和字段名是否拼对、join条件是否写全、group by是否包含所有非聚合字段

5.3 面试官视角:什么样的候选人能加分

最后从面试官的角度说几个很少有候选人能做到的加分项,这些在笔试中同样适用:

一是写SQL时主动考虑性能。我看到很多候选人的SQL能跑出正确答案,但扫描了全表、做了大量无用计算。如果能在答案里注明“这里加一个分区过滤条件”或“这里先过滤再做join”,立刻会加分不少。

二是对数据质量的敏感度。写出的SQL能考虑到重复数据、null值、极端值的情况,给处理逻辑做防御,这种意识在真实业务中极其重要。笔试答案里如果体现了“先用row_number去重”或“把字段为null时给默认值”,面试官对你的评价会明显提升。

三是沟通表达的清晰度。笔试不是只有编码,很多公司笔试会要求写解题思路。用简单的语言把逻辑说清楚,比晒高级语法更能体现真实水平。

6. 冲刺建议与个人经验分享

先把个人经验说在前面:这个行业的笔试确实越来越卷了,尤其是头部互联网公司和大厂数仓岗,SQL题目难度逐年上升,场景题越来越多。但有一个好消息是:高频考点其实是有限的,翻来覆去就是SQL窗口函数、Hadoop/Spark原理、数据倾斜、数仓建模这几个方向。只要把这些方向的题彻底吃透,笔试通过率会有质的飞跃。

关于复习材料的推荐,我个人的组合是:

  • SQL:牛客SQL题库 + 力扣数据库题库,双管齐下,按题型刷两遍
  • Hadoop/Spark:从官方文档过一遍核心概念,再看源码解析类文章,重点看HDFS写流程、MapReduce Shuffle、Spark Stage划分和Shuffle机制
  • 数仓:找一本维度建模的书通读,然后去真实数据集上练手,比如自己拉一份公开的订单数据,设计一套完整的分层数仓
  • 模拟面试:找朋友或者用AI工具进行模拟问答,重点是训练“把原理讲清楚”的能力,而不是背答案

最后再分享一个我在面试中最常用的小技巧:回答任何一道原理题,都按照“业务场景引入 -> 核心机制拆解 -> 优缺点分析 -> 实际应用建议”这个顺序组织语言。这个顺序的好处是让面试官感受到你有真正的实战经验,而不是在背题。比如回答Spark宽窄依赖,先说我遇到过的一个数据倾斜案例,然后引出宽依赖导致Shuffle,再对比窄依赖的流水线执行优势,最后给出优化的具体建议。

笔试没有捷径,但一定有方法。把精力花在高频考点上,每次刷题都当成一次技术输出的演练,坚持一个月就能看到明显效果。希望这篇文章能帮你少走一些弯路,在面试中拿到理想的结果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 8:01:49

什么是vibe coding:概念解析与TaoToken配置Trae实测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 8:01:11

PyTorch实现高光谱图像分类:2D CNN从数据预处理到实战全流程

第一次做高光谱图像分类实战,很多人的第一反应是直接上3D CNN或者各种注意力机制模型,结果数据预处理还没搞明白,就被复杂的网络结构折腾到怀疑人生。我的建议很直接:入门阶段就用PyTorch写一个2D CNN,先把高光谱图像分…

作者头像 李华
网站建设 2026/9/30 8:00:57

嵌入式软件面试高频考点全解析:从C/C++基础到工程实践

面试这种事,说到底就是一场信息战。嵌入式软件方向的面试尤其如此,考察范围横跨C/C语法、操作系统原理、单片机底层、通信协议、工程化工具链,甚至还包括调试习惯和单元测试意识。我自己这些年既被人面过,也坐到桌对面看过不少候选…

作者头像 李华
网站建设 2026/9/30 8:00:40

C# 内存泄漏排查:从托管堆、非托管资源到 VS2022 诊断实战

1. 先把话说清楚:C# 里的内存泄漏到底长什么样 C# 有 GC,很多人第一反应是"托管代码哪来的内存泄漏"。这个说法只对了一半。GC 能回收的是"没有任何根引用指向的对象",它管不了"你还拿着引用却不打算再用"的对…

作者头像 李华