我在使用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的内存,所以我不知道为什么我的内存不足。有没有人对此有任何想法?我使用JCuda 0.8.0RC和CUDA 8的发布版本确实如此,但我尝试下载RC版本的CUDA 8(8.0.27)以与JCuda 0.8.0RC一起使用让它发挥作用的一些问题。但是,如果版本兼容性可能会成为问题,我可以再试一次。
当然,100000 * 5000的矩阵非常大,我不需要在我的神经网络项目上使用更大的矩阵一段时间,但我想确信我可以使用所有8GB这张新卡的内存。谢谢你的帮助。
答案 0 :(得分:2)
<强> TL; DR:强>
致电
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类型不匹配。但只要分配不大于9百万兆字节(!),long
在这里应该没问题......)
但是comment by havogt
导致了正确的轨道。这里发生的事情 确实是整数溢出:实际值的计算
110000 * 5000 * Sizeof.FLOAT = 2200000000
默认情况下,使用Java中的 int
类型完成,这就是溢出发生的地方:2200000000大于Integer.MAX_VALUE
。结果将是否定值。当它转换为JNI层中的(无符号)size_t
值时,它将成为一个可笑的大正值,这显然会导致错误。
使用long
值进行计算时,通过显式转换为long
或将L
后缀附加到其中一个文字,该值将作为正确值传递给CUDA long
值为2200000000.