GDALWarp设置GDALWarpOptions::dfWarpMemoryLimit过大时处理失败

Posted wzzkaifa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GDALWarp设置GDALWarpOptions::dfWarpMemoryLimit过大时处理失败相关的知识,希望对你有一定的参考价值。

使用GDALWarp写了一个裁切图像的算法。在小内存的电脑没事,大内存的电脑就处理失败(32位也没问题),查看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过大时处理失败的主要内容,如果未能解决你的问题,请参考以下文章

部分GDAL工具功能简介

Gdal之投影转换、裁切、合并

图像重采样(CPU和GPU)

GDAL warp 太多点无法转换。它适用于相似的图像和来源

时钟设置在哪里设置?

QGIS基本设置和项目设置