仅在GTX1080上使用~2.2GB内存后,CUDA内存不足消息

仅在GTX1080上使用~2.2GB内存后,CUDA内存不足消息,cuda,out-of-memory,jcuda,Cuda,Out Of Memory,Jcuda,我正在使用JCuda,版本0.8.0RC和CUDA8.0在GTX1080GPU上进行矩阵乘法。我以行主向量的形式将两个矩阵A和B加载到设备中,并从设备中读取乘积矩阵。但我发现我比预期的更早用完了设备内存。例如,如果矩阵A的尺寸为100000*5000=5亿个条目=2GB的浮点值,则: cuMemAlloc(MatrixA, 100000 * 5000 * Sizeof.FLOAT); 很好。但是如果我将行数从100000增加到110000,我会在这个调用中得到以下错误(这是在为矩阵B和C分配

我正在使用JCuda,版本0.8.0RC和CUDA8.0在GTX1080GPU上进行矩阵乘法。我以行主向量的形式将两个矩阵A和B加载到设备中,并从设备中读取乘积矩阵。但我发现我比预期的更早用完了设备内存。例如,如果矩阵A的尺寸为100000*5000=5亿个条目=2GB的浮点值,则:

cuMemAlloc(MatrixA, 100000 * 5000 * Sizeof.FLOAT); 
很好。但是如果我将行数从100000增加到110000,我会在这个调用中得到以下错误(这是在为矩阵B和C分配内存之前发生的,因此这些不是问题的一部分):

问题是,在设备上分配一个这样大小的矩阵只需要2.2GB,而GTX1080有8GB的内存,所以我不明白为什么内存不足。有人对此有什么想法吗?的确,我在CUDA 8的发行版中使用了JCuda 0.8.0RC,但我尝试下载了CUDA 8的RC版本(8.0.27)以与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
它应该会起作用


的最后一个参数的类型为
size\u t
。这是用于“任意”大小的特定于实现的无符号整数类型。Java中最接近的原语类型是
long
。通常,CUDA中的每个
size\u t
都映射到JCuda中的
long
。在这种情况下,Java
long
作为
jlong
传递到JNI层,对于实际的本机调用,这只是转换为
size\t

(Java中缺少无符号类型和C中奇数过多的整数类型仍然会导致问题。有时,C类型和Java类型不匹配。但只要分配不超过900万TB(!),这里的
就可以了……)

但这是通向正确轨道的线索。这里发生的实际上是一个整数溢出:实际值的计算

110000 * 5000 * Sizeof.FLOAT = 2200000000
默认情况下,使用Java中的
int
类型完成,这就是溢出发生的地方:2200000000大于
整数.MAX\u值。结果将是负值。当这个值被转换为JNI层中的(unsigned)
size\t
值时,它将变成一个非常大的正值,这显然会导致错误


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

tl;医生:

打电话的时候

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

cuMemAlloc(MatrixA, 110000L * 5000 * Sizeof.FLOAT); 
//                        ^ use the "long" literal suffix here
它应该会起作用


的最后一个参数的类型为
size\u t
。这是用于“任意”大小的特定于实现的无符号整数类型。Java中最接近的原语类型是
long
。通常,CUDA中的每个
size\u t
都映射到JCuda中的
long
。在这种情况下,Java
long
作为
jlong
传递到JNI层,对于实际的本机调用,这只是转换为
size\t

(Java中缺少无符号类型和C中奇数过多的整数类型仍然会导致问题。有时,C类型和Java类型不匹配。但只要分配不超过900万TB(!),这里的
就可以了……)

但这是通向正确轨道的线索。这里发生的实际上是一个整数溢出:实际值的计算

110000 * 5000 * Sizeof.FLOAT = 2200000000
默认情况下,使用Java中的
int
类型完成,这就是溢出发生的地方:2200000000大于
整数.MAX\u值。结果将是负值。当这个值被转换为JNI层中的(unsigned)
size\t
值时,它将变成一个非常大的正值,这显然会导致错误


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

如果你把它作为一个整体来分配,那么它需要是一个连续的内存块,这有时是很难实现的。如果可能的话,如果你把它分成更小的块并分配更多次,分配就更容易了。谢谢-这是我要研究的问题。你的数字还表明你可能会在库中的某个地方遇到整数溢出问题。你能试着分配2^31和2^31-1字节来检查吗?太棒了!数组维度131072*4096(x4)=2^31字节会给出错误,而131071*4096(x4)<2^31字节不会给出错误。与65536*8192和65535*8192相同。那么,除了分区之外,可能没有办法解决这个问题了吗?我在这里:-)cuMemAlloc
的最后一个参数是
long
,它在内部简单地转换为
size\u t
,但是计算是使用
int
进行的,因此
110000*5000*Sizeof.FLOAT
的计算将在java端溢出。请尝试
(long)110000…
(或使用
L
后缀表示文字)。如果它仍然不工作,给我一个便条。如果你把它作为一个整体分配,那么它需要是连续的内存块,这是很难做到的