GDALWarp设置GDALWarpOptions::dfWarpMemoryLimit过大时处理失败
2016-04-08 21:04
429 查看
使用GDALWarp写了一个裁切图像的算法,在小内存的电脑没事,大内存的电脑就处理失败(32位也没问题),查看GDAL的日志发现下面的错误信息:
从上面的日志中可以看出,居然申请内存失败了,见过小内存的机器申请内存失败的,没见过大内存的机器申请内存失败,很郁闷。
对比了小内存机器和大内存机器输入的数据,所有的参数都一样,除了GDALWarpOptions::dfWarpMemoryLimit这个。由于程序需要处理大量的数据,而且机器的内存也很大(128GB),所以就在程序启动之后先获取了系统的空闲内存,然后将空闲内存的四分之一设置给了dfWarpMemoryLimit这个参数(大内存机器这个值大概25GB左右)。将这个值手动改小,程序正确处理了,看来就是这个参数的原因。
通过调试GDAL的代码,在文件gdalwarpoperation.cpp中的函数GDALWarpOperation::CreateKernelMask中有下面的代码(SVN版本库中的代码行数大致在2059行,其他所有的版本都有这个问题,已经提交gdal的bug库)
从上面的代码中看的话,其实一般情况下没有任何问题,除了一种情况,如果nXSize和nYSize很大,比如我日志中的(31260*24550+nExtraElts)*4,即使nExtraElts=0,结果也会超过int的存储范围导致数据溢出,从而nBytes的值就会变成负数,进而分配内存的时候就失败了。下面是修改后的代码:
下面的图是GDAL出错时的各个变量的信息。
Fri Apr 08 17:39:02 2016: GDAL: GDALOpen(E:/Out/TRIPLESAT_1_PAN_L1_20160330024710_000315VI_005.tif, this=000000000508EB40) succeeds as GTiff. Fri Apr 08 17:39:02 2016: GDAL: GDALDriver::Create(GTiff,E:\xxx/TRIPLESAT_1_PAN_L1_20160330024710_000315VI_005_20160406003001_001.tif,31260,24550,1,UInt16,0000000000000000) Fri Apr 08 17:39:04 2016: WARP_TIMING: Output buffer read: 2s Fri Apr 08 17:39:07 2016: WARP_TIMING: Input buffer read: 3s Fri Apr 08 17:39:07 2016: CPLError: Out of memory allocating -1225110252 bytes for UnifiedSrcDensity mask. ERROR 2: Out of memory allocating -1225110252 bytes for UnifiedSrcDensity mask.
从上面的日志中可以看出,居然申请内存失败了,见过小内存的机器申请内存失败的,没见过大内存的机器申请内存失败,很郁闷。
对比了小内存机器和大内存机器输入的数据,所有的参数都一样,除了GDALWarpOptions::dfWarpMemoryLimit这个。由于程序需要处理大量的数据,而且机器的内存也很大(128GB),所以就在程序启动之后先获取了系统的空闲内存,然后将空闲内存的四分之一设置给了dfWarpMemoryLimit这个参数(大内存机器这个值大概25GB左右)。将这个值手动改小,程序正确处理了,看来就是这个参数的原因。
通过调试GDAL的代码,在文件gdalwarpoperation.cpp中的函数GDALWarpOperation::CreateKernelMask中有下面的代码(SVN版本库中的代码行数大致在2059行,其他所有的版本都有这个问题,已经提交gdal的bug库)
if( *ppMask == NULL ) { int nBytes; //this line should be GIntBig nBytes; if( nBitsPerPixel == 32 ) nBytes = (nXSize * nYSize + nExtraElts) * 4; else nBytes = (nXSize * nYSize + nExtraElts + 31) / 8; *ppMask = VSI_MALLOC_VERBOSE( nBytes ); if( *ppMask == NULL ) { return CE_Failure; } memset( *ppMask, nDefault, nBytes ); }
从上面的代码中看的话,其实一般情况下没有任何问题,除了一种情况,如果nXSize和nYSize很大,比如我日志中的(31260*24550+nExtraElts)*4,即使nExtraElts=0,结果也会超过int的存储范围导致数据溢出,从而nBytes的值就会变成负数,进而分配内存的时候就失败了。下面是修改后的代码:
if( *ppMask == NULL ) { GIntBig nBytes; if( nBitsPerPixel == 32 ) nBytes = ((GIntBig )nXSize * nYSize + nExtraElts) * 4; else nBytes = ((GIntBig )nXSize * nYSize + nExtraElts + 31) / 8; *ppMask = VSI_MALLOC_VERBOSE( nBytes ); if( *ppMask == NULL ) { return CE_Failure; } memset( *ppMask, nDefault, nBytes ); }
下面的图是GDAL出错时的各个变量的信息。
相关文章推荐
- GDALWarp设置GDALWarpOptions::dfWarpMemoryLimit过大时处理失败
- 关于产品的几个问题分析(来自京东产品经理笔试题)
- 一个优秀的数据产品经理是怎样炼成的?
- .Net 三款工作流引擎比较:WWF、netBPM 和 ccflow
- 认识产品经理(一)
- 产品经理入门方法论
- 以叫车软件为例,看高阶产品经理都是怎么分析问题的
- 修改npm下载模块的安装位置
- 使用npm安装一些包失败了的看过来(npm国内镜像介绍)
- 常用安装rpm包--必备命令
- 3.6-ansible安装rpm包管理服务
- MRD文档的写作----产品经理深入浅出课程
- package.json for NPM 文件详解
- 终于将tiny-sdpm+intellij idea+mysql+jettyt运行成功
- 尝试将 SCRIPT ompbox\private\ompmex 作为函数执行
- 你的一天 VS 50K产品经理的一天
- 论淘宝运营与互联网PM。
- rpm package installed problem
- Activiti源码分析
- JBPM4关于Assignee动态获取------OA系统工作流环节问题