Выделение большого объема памяти и использование size_t? - PullRequest
3 голосов
/ 28 сентября 2011

В моем приложении я выделяю память для хранения «объемных данных», которые считываются из стека растровых изображений.

Я сохранил данные в «unsigned char» и, во время выделения, сначала пытаюсь выделить непрерывный блок памяти для целых данных. Если происходит сбой, то пытается распределить распределение (один маленький блок памяти для каждого изображения) .

unsigned char *data;

вот мой метод выделения памяти, я вызываю с помощью "tryContinouseBlock = true".

 bool RzVolume::initVolumeData(int xsize, int ysize, int zsize, int bbpsize,bool tryContinouseBlock) {
        this->nx = xsize;
        this->ny = ysize;
        this->nz = zsize;
        this->bbp_type=bbpsize;

        bool succ = false;

        if (tryContinouseBlock) {
            succ = helper_allocContinouseVolume(xsize, ysize, zsize, bbpsize);
        }

        if (!succ) {
            succ = helper_allocScatteredVolume(xsize, ysize, zsize, bbpsize);
        } else {
            isContinousAlloc = true;
        }
        if (!succ) {
            qErrnoWarning("Critical ERROR - Scattered allocation also failed!!!!");
        }
        return succ;

    }



    bool RzVolume::helper_allocContinouseVolume(int xsize, int ysize, int zsize,
            int bbpsize) {
        try {
            data = new unsigned char*[1];
            int total=xsize*ysize*zsize*bbpsize;
            data[0] = new unsigned char[total];
            qDebug("VoxelData allocated - Continouse! x=%d y=%d Z=%d bytes=%d",xsize,ysize,zsize,xsize * ysize * zsize * bbpsize);
        } catch (std::bad_alloc e) {
            return false;
        }

        return true;

    }

bool RzVolume::helper_allocScatteredVolume(int xsize, int ysize, int zsize,
        int bbpsize) {
    data = new unsigned char*[zsize];
    //isContinousAlloc=false;
    int allocCount = 0;
    try { //Now try to allocate for each image
        for (int i = 0; i < zsize; i++) {
            data[i] = new unsigned char[xsize * ysize];
            allocCount++;
        }
    } catch (std::bad_alloc ee) {
        //We failed to allocated either way.Failed!

        //deallocate any allocated memory;
        for (int i = 0; i < allocCount; i++) {
            delete data[i];
        }
        delete data;
        data = NULL;
        return false;
    }
    qDebug("VoxelData allocated - Scattered!");
    return true;
}

Я хочу, чтобы этот код работал как на 32-битной, так и на 64-битной платформах.

Теперь проблема в том, что даже в 64-битной среде (с памятью 12 ГБ) метод helper_allocContinouseVolume () завершается неудачно, когда я загружаю (1896 *1816* 1253) размер данных (с bbpsize = 1). Из-за этого я использую тип данных "int" для доступа к адресу памяти, а максимальное значение "int" равно 4294967295.

В 32-битной и 64-битной среде следующий код дает значение «19282112».

 int sx=1896;
 int sy=1816;
 int sz=1253;
 printf("%d",sx*sy*sz);

где правильное значение должно быть "4314249408".

Так какой тип данных я должен использовать для этого? Я хочу использовать один и тот же код в 32-битной и 64-битной средах.

Ответы [ 3 ]

2 голосов
/ 28 сентября 2011

Я часто сталкиваюсь с той же проблемой при работе на рабочих станциях с> 32 ГБ памяти и большими наборами данных.

size_t обычно является правильным типом данных, который следует использовать для всех индексов в таких ситуациях, поскольку он «обычно» соответствует размеру указателя и остается совместимым с memcpy() и другими библиотечными функциями.

Единственная проблема заключается в том, что в 32-разрядной системе может быть сложно обнаружить случаи переполнения. Поэтому может быть целесообразно использовать отдельный этап вычисления памяти с использованием максимального целочисленного размера, чтобы увидеть, возможно ли это даже на 32-разрядной версии, чтобы вы могли справиться с этим изящно.

1 голос
/ 28 сентября 2011

size_t определяется как достаточно большой, чтобы описать наибольший допустимый размер объекта. Так что, как правило, при выделении объектов это правильный размер для использования.

ptrdiff_t определено, чтобы иметь возможность описать разницу между любыми двумя адресами.

Используйте тот, который соответствует вашей цели. Таким образом, вы будете уверены, что он имеет соответствующий размер.

1 голос
/ 28 сентября 2011

Использование ptrdiff_t от <stddef.h>.

Причина: он подписан, что позволяет избежать проблем с неявным продвижением, где задействовано unsigned, и имеет необходимый диапазон в любой системе, кроме 16-битной (в формальной версии он работает также и в 16-битной системе, но это потому, что формальное имеет глупое требование не менее 17 ( sic ) бит).

...