You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

cv::cuda::GpuMat::create分配高窄矩阵时显存远超申请量问题

问题复现环境与测试现象

运行环境为搭载CUDA 11.6、支持CUDA加速的最新版OpenCV 4.x。

首次测试在GPU设备内存中分配GpuMat图像,实现代码如下:

cv::cuda::GpuMat test1;
test1.create(100, 1000000, CV_8UC1);

使用nvidia-smi工具采集create函数调用前后的进程显存占用:

Before:
|    0   N/A  N/A    372354      C   ...aur/example_build/example      199MiB |
After:
|    0   N/A  N/A    389636      C   ...aur/example_build/example      295MiB |

本次显存增量约100MB,与理论申请的单通道8位100*1000000像素矩阵的内存大小一致,符合预期。

交换矩阵宽高参数开展第二次测试,分配代码如下:

cv::cuda::GpuMat test1;
test1.create(1000000, 100, CV_8UC1);

nvidia-smi采集到的显存占用结果如下:

Before:
|    0   N/A  N/A    379124      C   ...aur/example_build/example      199MiB |
After:
|    0   N/A  N/A    379124      C   ...aur/example_build/example      689MiB |

两次申请的矩阵元素总数量完全一致,理论显存增量应相同,但本次测试显存增量接近490MiB,远高于预期。多场景验证发现,分配“高而窄”的矩阵时,显存占用最高可达理论值的5倍。

问题成因

该现象的核心是对cv::cuda::GpuMat的步长(Pitch)对齐分配规则存在认知偏差,本质是CUDA硬件内存访问要求带来的必然设计:

  • CUDA全局内存访问有严格的对齐约束,为了实现内存合并访问、避免非对齐访问带来的数倍性能损失,OpenCV CUDA模块分配GpuMat内存时,不会直接按cols * elemSize()计算单行占用空间,而是会将每行的长度向上对齐到固定的内存对齐边界(OpenCV 4.x CUDA模块默认对齐边界为512字节)。矩阵实际占用显存的计算公式为rows * step[0],其中step[0]就是对齐后的单行字节数,而非直觉上的cols * elemSize()。
  • 第一次测试的矩阵为100行、1000000列,单通道8位格式下原始单行长度为1000000字节,对齐到512字节边界后仅产生极少量冗余,总占用约100MiB,和测试结果吻合。
  • 第二次测试的矩阵为1000000行、100列,单通道8位格式下原始单行长度仅100字节,对齐到512字节边界后,每行实际占用512字节,总占用为1000000 * 512 = 512000000字节 ≈ 488MiB,和测试测得的490MiB增量完全匹配。
  • 对于列数远小于对齐边界的高窄矩阵,每行的对齐冗余会被极高的行数放大:测试中观察到的最高5倍占用,刚好对应单通道8位格式下100列左右的矩阵对齐到512字节的比例(512/100≈5.12),完全符合规则表现。列数越小、行数越高,对齐冗余的占比就越高。
  • 该对齐规则不是OpenCV独有设计,是所有CUDA生态矩阵运算库的通用逻辑,包括CUDA原生NPP、PyTorch、TensorRT等的张量/矩阵分配都会遵循相同的对齐原则,属于必要的性能换空间开销。
  • 可直接读取GpuMat的step属性(即单行步长)验证该结论,第二次测试中打印test1.step会得到值为512,远大于直觉预期的100字节。

内容的提问来源于stack exchange,提问作者Winotix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:15:42