准备面试中学习的一些内容

博客园 首页 新随笔 联系 订阅 管理

1.栈和堆的区别

可以视为临时变量和手动申请内存空间的变量的区别
func example() {
a := 10 // 分配在栈上
b := new(int) // b 是在堆上分配的一个 int 指针
*b = 20
}
1.栈的内存分配是连续的,堆分配需要查找空闲块
2.栈是编译器自动分配和释放,堆需要自己申请空间
3.栈的内存小,堆的内存大
4.栈是后进先出,堆是任意顺序

2.进程和线程的区别

进程

有自己独立的物理内存空间,挂靠操作系统分配资源,使用的是堆和栈。是操作系统分配系统资源的最小单位。
┌───────────────┐ ← 高地址
│ 栈(Stack)│ ← 每个线程一个,向下增长
├───────────────┤
│ 堆(Heap)│ ← 动态申请内存区,向上增长
├───────────────┤
│ BSS段 │ ← 未初始化的全局变量
├───────────────┤
│ 数据段(Data)│ ← 初始化的全局/静态变量
├───────────────┤
│ 代码段(Text)│ ← 程序指令(只读)
└───────────────┘ ← 低地址
查看对应部分所占内存的命令:
堆/栈: cat /proc/[pid]/maps 后面对应有[heap]/[stack] 标志的代表的就是对应的堆/栈
bss/data/text: readelf-S /bin/ls 路径可以根据自己的来,对应字段下标志的大小就是所占的内存

线程

轻量级进程,是操作系统调度(CPU调度)执行的基本单位,使用的是堆和栈。
栈区对于线程来说不共享,但是堆是共享的。
线程在创建的时候就会分配一块单独的栈空间(1MB-8MB)
就像每个函数里面的临时变量是不共享的,但是申请了空间的变量是可以共享的。

区别

  • 进程之间不共享内存,线程之间会共享内存
  • 进程切换操作成本高,线程较低
  • 进程通信方式是管道、消息队列,线程是内存共享、锁
  • 进程之间可并发,一个进程中的多个线程也可并发
  • 进程拥有系统资源(静态资源:地址空间、文件系统状态、信号处理handler)
    线程不拥有系统资源(动态资源:运行栈、调度的控制信息、待处理的信号集)
  • 进程有自己独立的地址空间,崩溃后不会对其他进程产生影响。
    线程是一个进程中的不同执行路径,一个线程没有自己的地址空间,死掉(死锁)之后该进程中的所有线程都会死掉。多进程的程序比多线程健壮,但是效率差。

亲缘性

进程/线程只在某个cpu上运行,不允许调度到其他核心

场景 解释
提升缓存命中率 绑定到某个核心可以利用该核心的缓存数据(L1/L2),避免频繁调度导致缓存失效
减少上下文切换开销 如果任务老被调到不同核心,会产生额外的CPU上下文切换开销
控制资源分配 在多核机器上,进行线程分离,比如一个核负责网络线程,另一个核负责 IO,可以提升吞吐量
性能调优 在性能测试、实时系统(如游戏引擎、工业控制)中,有时会强制绑定特定线程运行在特定 CPU 上

taskset -c 0 ./your_program # 将程序绑定在 CPU 0 上运行
taskset -p <PID>//查看当前进程亲缘性

协程

协程通过程序切换,消耗资源少,通过栈实现。goroutine就是协程(轻量级线程,依赖于线程运行但并不是线程,共享一个线程的栈堆等所有空间),程序的执行路径是线程,所有执行路径的总体是进程
协程是在用户态执行,开销很小,速度很快,性能得到了极大的提升。
协程是可中断的,协程可以存储中断前的状态,并且在中断后恢复时继续使用之前的状态(协程本身不会自动存储和恢复中断前的状态,但可以手动保存当前状态并在恢复时继续运行)。
保存的内容一般是:
1.当前处理的任务 ID 或数据
2.已完成进度(比如处理了 100 条数据中的前 20 条)
3.关键变量值(缓存、临时数据)
4.状态机位置(在哪一步暂停)
手动保存可以通过redis/mysql/文件存储state,context.Context + 状态存储,来恢复

协程较线程的优势:
1.没有线程切换,少了很多io开销,由程序本身控制,较多线程性能提升较大,虽然协程的调度由用户自己控制(例如 Go 语言的 Goroutine 由 Go runtime 调度),它的调度并不像线程那样由操作系统内核管理,因此创建和销毁的开销极低。而且协程能够在同一个线程上并发执行,大大减少了上下文切换的成本,从而提高了效率。
2.不需要锁,一个线程没有同时写的冲突,共享资源不加锁,只用判断状态

posted on 2025-04-25 11:17  Despacit  阅读(18)  评论(0)    收藏  举报