(嵌入式面经)第11章 20+公司面经杂谈(二):影石insta360、汇川、星纵科技、金风科技

本篇涉及的所有问题概要:大家可以试试在看参考答案前,提前尝试解答,以便明确自身知识点的不足部分!

1. 在多线程中,其中一个线程调用在其他地方的函数时,函数的参数会存在哪里?

2. 写时复制技术有了解过吗,说下实际应用的案例?

3. 有没有遇到过栈爆炸的情况?

4.了解systick定时器吗,说说有什么作用?

5.有没有遇到SPI时钟不匹配或者乱序的问题,如何解决的?

6.CPU寄存器中哪几个比较关键?

7.FREERTOS线程切换中大概做了哪些工作?

8.看你有涉及内存管理,那你知道动态内存管理的方法,有哪些吗?

9. 在我们平常内存管理中,除了内存碎片,还会碰到什么难题吗?

10. 专栏订阅奖励(支持模仿)——个人创新点问答:你所设计的FreeRTOS PLUS中操作系统中是怎么去做/检测有没有内存泄漏的?

---------------------------------------------------------------------------------------------------

1. 在多线程中,其中一个线程调用在其他地方的函数时,函数的参数会存在哪里?

在多线程编程中,每个线程有自己独立的栈空间来存储函数的参数和局部变量。

因此,函数参数存储在调用该函数的线程的栈中,不会影响其他线程。

1. 线程栈的作用

多线程编程 中,每个线程都有自己的 独立栈,它的主要作用包括: ✅ 存储函数调用的局部变量(包括函数参数、局部变量、返回地址)。

维护函数调用状态(记录返回地址、执行上下文)。

支持递归调用(每次递归调用都会在栈上创建一个新的栈帧)。

2. 函数参数的存储

当线程调用一个函数时,函数的参数会被压入该线程的栈

  • 函数调用时,参数被存入栈,函数执行期间这些参数一直存在。
  • 函数返回后,栈上的参数会被销毁(栈帧弹出),释放给其他函数调用使用。

示例:线程调用函数,参数存储在栈上

value 的地址传递给 thread_func(),但 local_var 作为局部变量存储在线程的栈上。

3. 线程与栈的关系

(1)每个线程有独立栈

  • 每个线程在创建时分配独立的栈空间,用于存储局部变量和函数参数。
  • 即使多个线程调用同一函数,它们的局部变量和参数互不干扰
  • (2)线程栈的大小

    • 默认栈大小(Linux pthread):通常为 8 MB
    • 可调整栈大小

    4. 栈帧和函数调用

    函数调用时栈的变化

    每次函数调用都会创建一个新的栈帧,包含:

  • 函数参数
  • 局部变量
  • 返回地址
  • 示例:函数调用栈帧

    执行 funcB() 时,栈帧变化如下:

    | funcB() 栈帧 | // 进入 funcB() | funcA() 栈帧 | // 调用 funcA(),创建新栈帧,存储参数 5 | 局部变量 x |

    funcA() 执行完毕,其栈帧会被销毁,返回 funcB()

    5. 线程栈的线程安全性

    (1)为什么线程的栈是线程安全的?

    每个线程的栈是独立的,不会影响其他线程

    函数参数和局部变量在各自线程的栈上,互不干扰

    除非主动共享数据(如全局变量),否则栈上的变量是线程安全的

    (2)非线程安全的情况

    使用全局变量可能导致线程安全问题

    解决方案:使用互斥锁(Mutex)

    6. 结论

    函数的参数存储在调用线程的栈中,函数返回后该栈帧会被销毁

    每个线程拥有独立栈空间,确保线程调用相同函数时互不干扰

    局部变量和参数是线程安全的,但共享数据需要额外同步机制

    2. 写时复制技术有了解过吗,说下实际应用的案例?

    1. 什么是写时复制?

    写时复制(Copy-On-Write, COW) 是一种 内存优化技术,其核心思想是: ✅ 延迟数据复制,只有当数据被修改时才进行真正的拷贝。

    多个进程/线程可以共享相同的内存区域,避免不必要的复制,节省资源

    🚀 典型应用场景

    • 进程创建(Linux fork()
    • 字符串、数据结构(C++ std::string、智能指针)
    • 虚拟内存管理(内存页共享)

    2. 为什么需要写时复制?

    传统拷贝 方式中,当一个进程 调用 fork() 创建子进程 时,整个进程的内存都会被复制一遍

    这会 浪费大量内存,尤其是当子进程 只是读取数据,而不修改时,这部分拷贝完全没必要。

    写时复制的解决方案

    1. 初始时,父子进程共享相同的内存页(只读)
    2. 只有当子进程或父进程尝试修改数据时,才触发真正的内存拷贝(COW 机制)
    3. 这样只有被修改的页面才会被复制,避免不必要的拷贝,提高性能

    示例(写时复制)

    如果 B 修改 [ 共享页 2 ]

    🚀 只复制修改的页,而不是整个进程的内存,节省内存资源!

    3. Linux fork() 机制与 COW

    fork() 的默认行为

    • 在 Linux 中,fork()不会立即复制整个父进程的内存页,而是通过写时复制(COW)技术,父子进程共享相同的内存页
    • 只有在 父进程或子进程尝试写入数据 时,才会触发内存页的复制

    示例(C 语言 fork()

  • varfork()不会立即复制,父子进程 共享相同的内存页
  • 子进程修改 var = 20,触发 COW,复制 var 变量的内存页
  • 父进程仍然保持 var = 10,因为它没有修改该变量
  • 4. 写时复制在 C++ STL 容器中的应用

    在 C++ 中,某些数据结构(如 std::stringstd::vector)也使用 写时复制(COW) 来优化性能。

    C++ std::string 的 COW

    • str2 = str1不会立即复制内存,而是共享 str1 的数据
    • str2[0] = 'X'触发 COWstr2获得独立副本,避免修改 str1

    C++11 之后,标准库已移除 std::string 的 COW,改用 std::move() 进行高效拷贝。

    5. 写时复制的优缺点

    优点

  • 减少不必要的内存拷贝(只在写入时复制)。
  • 提高内存利用率(多个进程/对象共享相同数据)。
  • 提高性能(避免频繁拷贝,大幅提升 fork() 性能)。
  • 缺点

    1. 增加了额外的逻辑开销(需要标记哪些数据是共享的)。
    2. 多线程环境可能需要额外的锁机制(避免多个线程同时修改)。

    6. 写时复制 vs 深拷贝 vs 浅拷贝

    COW 适用于只读多、写入少 的场景,避免不必要的拷贝,提高效率

    结论

    写时复制(Copy-On-Write, COW)是一种优化内存使用的技术,主要用于进程 fork()、C++ STL、数据库等场景

    通过 COW,多个对象可以共享相同数据,只有在修改数据时才真正分配内存,避免不必要的复制

    COW 适用于"读多写少" 的场景,如 fork() 进程创建、共享 std::string 数据、数据库事务

    3. 有没有遇到过栈爆炸的情况?

    1. 什么是栈爆炸?

    栈爆炸(Stack Overflow) 发生在 程序调用栈空间被耗尽 时,通常导致 程序崩溃

    🚀 常见原因

  • 递归调用没有终止条件(无限递归)。
  • 递归深度过大(栈帧过多,占用栈空间过大)。
  • 局部变量过大(单个函数栈帧消耗过多内存)。
  • 多线程程序,每个线程栈大小有限
  • 2. 栈爆炸的典型场景

    (1)递归没有终止条件

    如果递归函数没有合适的终止条件,它会一直递归调用自己,直到栈空间耗尽。

    示例

  • 每次 recursive_function() 调用自身,都会在 栈上分配新的栈帧
  • 递归不会终止,最终超出系统分配的栈空间,导致栈爆炸(Stack Overflow)
  • 修正方法

    (2)递归层次过深

    即使递归有终止条件,但如果 递归深度过大,依然会导致栈空间不足。

    示例

  • 大多数系统默认的 栈大小 只有 几 MB,比如 Linux 默认 8MB。
  • 100,000 次递归调用,每次调用都会消耗栈空间,最终导致溢出。
  • 修正方法

    • 使用循环代替递归(尾递归优化)

    • 增大栈大小(Linux ulimit -s 命令)

    (3)局部变量过大

    局部变量 存储在栈上,如果分配的变量过大,会导致栈空间耗尽。

    示例

  • 默认栈大小可能只有 8MB,一次性分配 1MB 局部数组,多个调用可能导致溢出。
  • 局部数组应改为 malloc() 申请堆内存
  • 修正方法

    (4)多线程栈空间不足

    在多线程程序中,每个线程都有自己的 独立栈(通常比主线程小,如 1MB)。

    示例

  • 线程栈大小一般较小(1MB),创建多个线程或者局部大数组可能导致 栈空间耗尽
  • 局部变量过大可能导致单个线程崩溃
  • 修正方法

    3. 如何防止栈爆炸?

    (1)优化递归

    • 确保递归有终止条件
    • 使用循环代替深度递归(尾递归优化)
    • 使用动态编程减少递归深度

    (2)避免大局部变量

    • 使用 malloc() 分配大数组,而不是栈上分配
    • 释放不再需要的堆内存,避免泄漏

    (3)增加栈大小

    • Linux 通过 ulimit -s unlimited 取消限制
    • pthread 线程手动设置更大栈空间

    (4)检测栈使用

    • 在嵌入式系统中,使用 栈监视工具 检查栈溢出
    • 使用 GDB 断点跟踪递归调用栈。

    结论

    栈爆炸(Stack Overflow)通常由递归过深、局部变量过大、多线程栈不足导致

    避免无限递归,使用尾递归优化、动态编程或循环替代递归

    合理管理内存,避免大数组分配在栈上,必要时增加栈空间

    4.了解systick定时器吗,说说有什么作用?

    1. 什么是 SysTick?

    SysTick(System Timer)是 Cortex-M4 内核 内置的 24 位递减定时器,嵌入在 NVIC(Nested Vectored Interrupt Controller) 中。

    它的主要特点包括:✅ 24-bit 递减计数器(最大计数 2^24 - 1 = 16,777,215)。

    计数完毕触发中断,可用于 周期性任务(如 OS 时基)。

    固定时钟源(通常是 SYSCLK 或内部时钟)。

    2. SysTick 的主要作用

    (1)普通定时器

    • SysTick 可以用作普通定时器,例如 精确延时、定时触发任务

    (2)OS 时基

    • FreeRTOS、RT-Thread 等实时操作系统(RTOS) 需要一个 固定的时钟节拍(Tick),SysTick 常用于 提供 OS 心跳,驱动 任务调度

    示例

    SysTick 周期性触发中断 --> 增加系统 Tick 计数器 --> 触发任务调度

    3. SysTick 计时原理

    SysTick 计数方式为 向下递减

    1. 当 SysTick 计数器(CURRENT)从 Reload 递减到 0 时:触发 SysTick 中断。计数器 自动重新加载Reload 值,继续递减。
    2. SysTick 计数频率 = 系统时钟(SYSCLK) / 预分频系数

    4. SysTick 寄存器

    SysTick 主要有以下 三个寄存器

    配置寄存器

    5. SysTick 配置示例

    示例:使用 SysTick 实现 1ms 定时

  • SysTick 每 1ms 触发一次中断
  • SysTick_Counter 作为计数器,用户可以使用 Get_SysTick() 获取当前时间。
  • 6. SysTick 在 RTOS(FreeRTOS)中的作用

    (1)为什么 RTOS 需要 SysTick?

    • RTOS 任务调度 依赖于 时基(Tick Timer),SysTick 作为 时钟源RTOS 提供固定节拍
    • 任务切换发生在 SysTick 中断 里,每次触发时会判断是否需要 切换任务

    (2)SysTick 在 FreeRTOS 中的配置

    FreeRTOS 需要重定义 SysTick_Handler

    配置 FreeRTOS 的时钟

    7. SysTick 的优缺点

    优点

    1. 内核自带,无需额外硬件,占用资源少。
    2. 适用于定时任务、OS 时基、

    剩余60%内容,订阅专栏后可继续查看/也可单篇购买

    作者简介:仅用几个月时间0基础天坑急转嵌入式开发,逆袭成功拿下华为、vivo、小米等15个offer,面试经验100+,收藏20+面经,分享求职历程与学习心得。 专栏内容:这是一份覆盖嵌入式求职过程中99%问题指南,详细讲解了嵌入式开发的学习路径、项目经验分享、简历优化技巧、面试心得及实习经验,从技术面,HR面,AI面,主管面,谈薪一站式服务,助你突破技术瓶颈、打破信息差,争取更多大厂offer。

    全部评论

    相关推荐

    运营3年修炼中接简历辅导:你的科研项目经历里,只写了你的动作,没有写你的思考和成果,不要只写使用什么进行了什么,这等于罗列你的任务,简历是为了突出你的优秀,你在什么样的任务背景下,克服了什么样的困难,针对性地做了哪些事情,最后达成了什么成果(用数据体现你的成果和效率)
    点赞 评论 收藏
    分享
    吴offer选手:学到了,下次面试也放张纸在电脑上,不然老是忘记要说哪几个点
    点赞 评论 收藏
    分享
    评论
    5
    13
    分享

    创作者周榜

    更多
    牛客网
    牛客企业服务