【问题标题】:CUDA out of memory message after using just ~2.2GB of memory on a GTX1080在 GTX1080 上仅使用 ~2.2GB 内存后的 CUDA 内存不足消息
【发布时间】:2016-11-10 01:41:45
【问题描述】:

我在 GTX1080 GPU 上使用 JCuda 进行矩阵乘法,版本 0.8.0RC 和 CUDA 8.0。我以行主向量形式将两个矩阵 A 和 B 加载到设备中,并从设备中读取乘积矩阵。但我发现我的设备内存比我预期的要早用完。例如,如果矩阵 A 的维度为 100000 * 5000 = 5 亿个条目 = 2GB 的浮点值,那么:

cuMemAlloc(MatrixA, 100000 * 5000 * Sizeof.FLOAT); 

工作正常。但是,如果我将行数或行数从 100000 增加到 110000,则在此调用中会出现以下错误(这是在矩阵 B 和 C 的内存分配之前发生的,因此这些不是问题的一部分):

Exception in thread "main" jcuda.CudaException: CUDA_ERROR_OUT_OF_MEMORY
at jcuda.driver.JCudaDriver.checkResult(JCudaDriver.java:344)
at jcuda.driver.JCudaDriver.cuMemAlloc(JCudaDriver.java:3714)
at JCudaMatrixMultiply.main(JCudaMatrixMultiply.java:84) (my code)

问题是在设备上分配这种大小的矩阵应该只需要大约 2.2GB,而 GTX1080 有 8GB 内存,所以我不明白为什么内存不足。有人对此有任何想法吗?确实,我将 JCuda 0.8.0RC 与 CUDA 8 的发行版一起使用,但我尝试下载 CUDA 8 (8.0.27) 的 RC 版本以与 JCuda 0.8.0RC 一起使用,但在使其工作时遇到了一些问题.但是,如果版本兼容性可能是问题,我可以再试一次。

当然,100000 * 5000 的矩阵非常大,在我的神经网络项目中我暂时不需要使用更大的矩阵,但我想确信我可以使用全部 8GB 内存在这张新卡上。感谢您的帮助。

【问题讨论】:

  • 如果你将它作为一个整体分配,那么它需要是连续的内存块,这有时很难实现。如果可能的话,如果将其分成更小的块并分配更多次,分配会更容易。
  • 谢谢 - 我会调查的。
  • 您的数字还表明您可能会在库中的某处遇到整数溢出问题。你能尝试分配 2^31 和 2^31-1 字节来检查吗?
  • 太棒了!数组尺寸 131072 * 4096 (x4) = 2^31 字节会给出错误,而 131071 * 4096 (x4)
  • 我在这里 :-) cuMemAlloc 的最后一个参数是 long,它在内部简单地转换为 size_t,但 计算 发生使用int - 所以110000 * 5000 * Sizeof.FLOAT 的计算已经在java端溢出。尝试(long)110000 ...(或使用L 后缀作为文字)。如果它仍然不起作用,请给我留言。

标签: cuda out-of-memory jcuda


【解决方案1】:

tl;博士:

调用时

cuMemAlloc(MatrixA, (long)110000 * 5000 * Sizeof.FLOAT); 
//                     ^ cast to long here

或者

cuMemAlloc(MatrixA, 110000L * 5000 * Sizeof.FLOAT); 
//                        ^ use the "long" literal suffix here

它应该可以工作。


cuMemAlloc 的最后一个参数是 size_t 类型。这是用于“任意”大小的特定于实现的 unsigned 整数类型。 Java 中最接近的原始类型是long。通常,CUDA 中的每个size_t 都映射到JCuda 中的long。在这种情况下,Java long 被作为 jlong 传递到 JNI 层,这只是简单地转换为 size_t 以进行实际的本地调用。

(Java 中缺少无符号类型和 C 中奇数过多的整数类型仍然会导致问题。有时,C 类型和 Java 类型不匹配。但只要分配不大于900 万太字节 (!),long 在这里应该没问题...)

但是comment by havogt 导致了正确的轨道。这里发生的确实是整数溢出:实际值的计算

110000 * 5000 * Sizeof.FLOAT = 2200000000

默认使用 Java 中的 int 类型完成,这就是发生溢出的地方:2200000000 大于 Integer.MAX_VALUE。结果将是一个值。当这被转换为 JNI 层中的(无符号)size_t 值时,它将变成一个可笑的大 值,这显然会导致错误。

使用long 值进行计算时,通过显式转换为long 或将L 后缀附加到文字之一,该值将作为正确的long 值2200000000 传递给CUDA .

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2021-05-20
    • 2022-10-17
    • 2011-10-12
    • 2019-06-06
    • 2021-12-16
    • 2020-05-04
    相关资源
    最近更新 更多