根据面经准备面试-第二期-2026字节跳动嵌入式软开提前批
还想看哪家公司可以评论区评论,有些笔误证明自己没开
2.FreeRTOS任务调度,调度策略
3、优先级反转
4、QT和LVGL
5、OTA
6、对此加密和非对称加密
7、线程和进程,进程间的通信方式
8、线程同步机制9、死锁
10、堆、栈、内存分区
11、heap4的算法
12、tcp,udp,三次握手,四次挥手
13、DNS
14、智能指针
15、虚函数
16、链表
17、手撕——回文字符串判断
18、手撕——翻转链表
2. FreeRTOS 任务调度及调度策略
答:freertos的任务调度是抢占式的,核心是根据任务优先级决定执行哪个任务
核心:优先级抢占:高优先级任务就绪时,立即打断低优先级级任务(除非低优先级持有互斥锁)
时间片轮转:同优先级任务采用时间片轮转的方式(开启configuse——time-slicing),每个任务运行一个时间片(由configtick———rate-hz决定,10ms后切换)
协作式调度:通过taskyteld主动让出cpu,需关闭抢占,
3.优先级反转:低优先级任务持有高优先级任务需要的资源时,导致高优先级任务被阻塞,中等优先级任务反而能运行
打破优先级高的先执行
- 任务 L(低优先级)获取互斥锁 M;
- 任务 H(高优先级)需要锁 M,因 L 持有而阻塞;
- 任务 M(中优先级)就绪,抢占 L 的 CPU,导致 H 长时间阻塞。
解决办法:优先级继承:低优先级任务持有高优先级任务需要的锁时,临时提升到高优先级,防止被中等优先级任务抢占(FreeRTOS 的vSemaphoreCreateBinary()互斥锁默认支持)。
4.QT 和 LVGL 的区别
QT LVGL
定位 | 跨平台 GUI 框架(支持桌面 / 嵌入式) | 轻量级嵌入式 GUI 库(专注资源受限设备) |
资源占用 | 较大(需 MB 级内存) | 极小(KB 级内存,适合 MCU) |
适用场景 | 复杂界面(如工业控制屏、车载系统) | 简单界面(如智能手表、家电显示屏) |
渲染方式 | 支持硬件加速(OpenGL) | 主要软件渲染,支持部分硬件加速 |
开发语言 | C++ | C |
5、OTA
定义:通过无线方式(如 Wi-Fi、蓝牙)远程升级设备固件,无需物理连接。
流程:
- 设备从服务器下载固件包(需校验版本号,避免重复升级);
- 校验固件完整性(如 CRC、MD5)和合法性(如签名验证);
- 将固件写入备用分区(双分区设计,避免升级失败变砖);
- 重启设备,从新分区启动,若失败则回退到原分区。
这里拓展一下IAP,设备自己升级自己的程序。简单说,就是设备里已经有一个能运行的程序(叫 “bootloader” 或 “APP1”),这个程序可以把新的固件(比如新 APP)写到自己的存储里,然后重启运行新程序。
关系:OTA 是 “远程获取新固件” 的过程,而 IAP 是 “设备本地安装新固件” 的核心技术。没有 IAP,OTA 拿到新固件也没法升级
IAP核心原理:设备存储(flash),分成两个区域
boot loader区域,进门线运行程序,负责检查是否有新固件,如果有就启动升级(IAP的核心)
app区域,平时正常工作区域
需要升级时,1.新固件通过OTA传到设备,先存在临时区域
2.bootloader启动,发现有新固件,就从临时区域搬到app区域,覆盖掉旧程序
3。搬完后重启,bootloader直接运行app区域
IAP具体流程,以单片机+flash
1.给存储分区,吧设备flash分成3个区域:bootloader放IAP升级程序
app区:放正常的工作程序
临时缓冲区域:暂存OTA下载的新固件(也可以用内存,内存小分段存)
2.正常运行,bootloader跳转到app
设备上电先运行bootloader,检查是否需要升级,(比如看一个标记位:如果用户触发了升级,或 OTA 下载了新固件,就设为 “需要升级”)
3.触发升级:收到新固件
- 比如通过 OTA 从服务器下载新固件(假设叫 “new_app.bin”),存到临时缓冲区。
- 下载完成后,设置一个 “升级标记”(比如在 Flash 的某个固定地址写 1,表示需要升级),然后重启设备
- 检测到 “升级标记 = 1”,开始执行升级逻辑。
- 读取临时缓冲区的新固件数据,逐段写到 APP 区(覆盖旧程序)。注意:写 Flash 时要先擦除对应区域(Flash 特性:必须先擦除才能写)。
- 写完后,校验新固件是否完整(比如算 MD5 值,和服务器给的对比,防止下载出错)。
4. IAP 核心:Bootloader 写入新固件
设备重启,再次运行 Bootloader:
5. 完成升级:清除标记,跳转新 APP
- 校验通过后,清除 “升级标记”(写 0),删除临时缓冲区的旧固件。
- 重启设备,Bootloader 检测到 “不需要升级”,跳转到 APP 区,此时运行的就是新程序了。
6. 异常处理:防止变砖
- 如果写固件时突然断电,重启后 Bootloader 发现 “升级标记 = 1 但 APP 区不完整”,会等待重新下载固件后再次升级。
- 如果新固件校验失败(比如损坏),Bootloader 会保留旧 APP,提示升级失败。
6.对称加密与非对称加密
回答:对称加密(如 AES、DES),加密和解密用同一密钥,快(适合大数据量,如文件),依赖密钥保管(泄露则不安全)
非对称加密(如 RSA、ECC),公钥(公开)加密,私钥(保密)解密,慢(适合小数据,如密钥交换),公钥公开不影响安全,私钥保密即可
结合使用:HTTPS 中,先用非对称加密交换对称密钥(如 RSA),再用对称加密传输数据(如 AES),兼顾安全和效率。
7、线程和进程,进程间的通信方式
进程:系统资源分配的基本单位,有独立内存空间,切换开销大
线程:进程内的执行单元,共享进程内存,切换开销小,是调度的基本单位
进程间通信的方式
管道,匿名管道,父子进程,命名管道,基于文件系统
消息队列,内核中的消息链表,进程按类型收发消息
共享内存,最快的进程间通信方式,内核
- 信号量:用于同步(如控制资源访问次数)。
- 信号:进程间异步通知(如
SIGINT终止进程)。
8、线程同步机制
线程共享线程资源,需要同步机制避免冲突
互斥锁,独占资源,同一时间仅仅一个线程访问
条件变量:线程间同步,生产者消费者模型,生产者通知消费者有数据
信号量:控制并发树,允许3个线程同时访问资源
读写锁:读多写少场景优化,多个读线程可同时访问,写线程独占
原子操作:无锁同步(如atomic_int,适合简单计数)
9、死锁
定义:两个或多个线程互相等待对方释放资源,导致永久阻塞。
必要条件:
- 互斥:资源只能被一个线程持有;
- 持有并等待:线程持有部分资源,同时等待其他资源;
- 不可剥夺:资源不能被强制剥夺;
- 循环等待:线程间形成等待环路(如 A 等 B 的资源,B 等 A 的资源)。
预防方法:
- 按固定顺序申请资源(打破循环等待);
- 申请资源时一次性获取所有需要的资源(打破持有并等待);
- 超时释放资源(如
pthread_mutex_timedlock)。
10、堆、栈、内存分区
内存分区:
- 栈:存放局部变量、函数参数,由编译器自动分配释放(如
int a = 10;),大小固定(通常几 MB),速度快。 - 堆:动态内存(如
malloc/new分配),需手动释放(否则内存泄漏),大小灵活(可到 GB 级),速度较慢。 - 全局 / 静态区:存放全局变量、静态变量(
static),程序启动时分配,结束时释放。 - 常量区:存放字符串常量(如
"hello"),只读。 - 代码区:存放程序指令(二进制代码),只读。
例如:int g_var;(全局区),void func() { int s_var; }(栈),int *p = malloc(10);(堆)。
11、heap4的算法
heap4 是 FreeRTOS 的内存分配算法,基于 “最佳适配” 策略,适合中小规模内存管理:
- 原理:内存被分成多个块,每个块包含 “大小 + 已分配标志” 的头部;
- 分配:遍历所有空闲块,选择能容纳请求大小的最小块,分割后分配;
- 释放:释放时检查相邻块是否空闲,若空闲则合并(减少内存碎片)。
12、tcp,udp,三次握手,四次挥手
TCP 与 UDP:
- TCP:面向连接、可靠传输(重传、确认机制)、流式数据(无边界),用于文件传输、HTTP 等。
- UDP:无连接、不可靠(无重传)、报文式(有边界),用于实时通信(如视频、DNS)。
TCP 三次握手(建立连接):
- 客户端→服务器:SYN(请求连接,序号 x);
- 服务器→客户端:SYN+ACK(同意连接,序号 y,确认 x+1);
- 客户端→服务器:ACK(确认 y+1)。(确保双方收发能力正常)
TCP 四次挥手(断开连接):
- 客户端→服务器:FIN(请求断开,序号 x);
- 服务器→客户端:ACK(确认 x+1);
- 服务器→客户端:FIN(准备断开,序号 y);
- 客户端→服务器:ACK(确认 y+1)。(因服务器可能还有数据要发,需分两次确认)
13、DNS
作用:将域名(如www.baidu.com)解析为 IP 地址(如180.101.50.242),方便用户记忆。
解析流程:
- 本地主机查询 DNS 缓存,若有则直接返回;
- 无缓存则查询本地 DNS 服务器(如路由器);
- 本地 DNS 服务器逐级查询根域名服务器→顶级域名服务器(
.com)→权威域名服务器,获取 IP 后返回给主机。
类型:A 记录(域名→IPv4)、AAAA 记录(域名→IPv6)、CNAME 记录(域名别名)。
14、智能指针
自动管理动态内存(new分配),避免内存泄漏(忘记delete)。
unique——ptr独占所有权,不允许拷贝,只能移动(std::move)
shared-ptr共享所有权,通过引用计数管理,计数为 0 时释放内存
weak_ptr配合shared_ptr使用,不增加引用计数,解决循环引用问题。
15、虚函数
实现多态(“一个接口,多种实现”),父类指针可调用子类重写的函数。
每个包含虚函数的类有一个 “虚函数表(vtable)”,存储虚函数地址;对象包含 “虚表指针(vptr)”,指向类的虚函数表,调用时通过 vptr 找到实际函数
16、链表
定义:由节点组成的线性数据结构,节点包含数据和指向下一节点的指针,无需连续内存。
类型:
- 单链表:每个节点只有 next 指针;
- 双向链表:节点有 prev 和 next 指针,可双向遍历;
- 循环链表:尾节点 next 指向头节点,可循环访问。
优点:插入 / 删除高效(O (1),只需修改指针);
缺点:随机访问差(O (n),需从头遍历)。
17、手撕——回文字符串判断
18、手撕——翻转链表
#面试问题记录#
阿里云工作强度 727人发布