register

位于SM内部,每个thread独有的,大小有限制(例如 64K 个 32-bit 寄存器),生命周期随thread 注意: Register Pressure (寄存器压力): 如果一个 Kernel 使用了过多的寄存器,会导致 SM 上能同时驻留的 Block 数量(Occupancy)减少,从而降低并行度 Register Spilling (溢出): 如果变量太多放不下,数据会被溢出到 Local Memory(虽然叫 Local,但在物理上是 Global Memory,非常慢),这会严重拖慢性能

shared_memory

位于SM内部,有大小限制,一个 Block 默认最多只能使用 48 KB(新架构要多一些),同一个block是共享的,生命周期同block,要注意bank conflict

constant memory

本质也是位于device memory中,但SM中有Constant Cache,靠命中cache加速,容量小通常64K,对于kernel只读 注意:当 Warp 中的所有线程都读取同一个地址时(例如读取卷积核的系数),数据会通过广播机制一次性发送给所有线程,效率极高

global memory

显存 注意:当一个 Warp (32个线程) 访问连续对齐的内存地址时,硬件会将这 32 个请求合并成最少数量的内存事务(Memory Transaction)。如果访问是乱序或跨步的(Strided),会导致带宽浪费严重

其它内存

local memory

实际上位于Global Memory (显存) 中 物理位置: 它实际上位于Global Memory (显存) 中。 为什么叫 Local? 仅仅是因为它的作用域是线程私有的(Local to thread) 什么时候用到? Register Spilling (寄存器溢出): 当你的 Kernel 变量太多,寄存器放不下时,编译器会被迫把多出来的变量塞到 Local Memory 里。 大数组: 如果你在 Kernel 里定义了一个很大的数组(比如 float arr[1000]),寄存器装不下,也会被放进这里。

Texture Memory (纹理内存)

L1 / L2 Cache (一级/二级缓存)

程序员不可见,但可以间接控制 L1 Cache: 位于 SM 内部。在很多现代架构(如 Ampere)中,L1 Cache 和 Shared Memory 实际上是同一块物理硬件。你可以配置这块硬件是多做 L1 缓存,还是多做 Shared Memory。 L2 Cache: 所有 SM 共享的中间层,连接 Global Memory。 重要性: 你通常不能直接编程控制它们(除了配置 L1/Shared 比例),但了解它们对于理解为什么有时候 Global Memory 并没有想象中那么慢(因为命中了 L2)非常重要。