我正在使用JCuda,版本0.8.0RC与CUDA 8.0在GTX1080 GPU上做矩阵乘法。我将两个矩阵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的内存,所以我不明白为什么我的内存不足。有人对此有什么看法吗?确实,我正在使用CUDA 0.8.0RC与CUDA 8的发布版本,但我试图下载CUDA 8(8.0.27)的RC版本与JCuda 0.8.0RC一起使用,并且有一些问题让它工作。但是,如果版本兼容性可能是问题,我可以再试一次。
100000 * 5000的矩阵当然是相当大的,在我的神经网络项目中,我不需要在一段时间内使用更大的矩阵,但我想确信我可以在这个新卡上使用所有8GB的内存。谢谢你的帮助。
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
。这是一个特定于实现的无符号整数类型,用于"任意"大小。在Java中最接近的可能的基本类型是long
。通常,CUDA中的每个size_t
都映射到JCuda中的long
。在这种情况下,Java long
作为jlong
传递到JNI层,并且对于实际的本机调用,它只是被转换为size_t
。
(Java中缺少无符号类型和C中过多的整数类型仍然会导致问题。有时候,C类型和Java类型不匹配。但只要分配不超过900万tb (!), long
在这里应该没问题…)
但是havogt
的评论是正确的。这里发生的情况是确实是一个整数溢出:
110000 * 5000 * Sizeof.FLOAT = 2200000000
在Java中默认使用 int
类型完成,这就是发生溢出的地方:2200000000大于Integer.MAX_VALUE
。结果将是一个负值。当它在JNI层中被转换为(无符号)size_t
值时,它将变成一个大得离谱的正值,这显然会导致错误。
当使用long
值进行计算时,通过显式转换为long
或通过将L
后缀附加到其中一个字面量,该值作为适当的long
值2200000000传递给CUDA。