Есть ли способ прочитать данные из CGImage без внутреннего кэширования? - PullRequest
0 голосов
/ 09 ноября 2018

Я борюсь с внутренним кэшированием (около 90 МБ для 15-мегапиксельного изображения) в CGContextDrawImage / CGDataProviderCopyData функциях.
Вот трассировка стека в профилировщике:

enter image description here

Во всех случаях IOSurface создается как «кэш» и не являетсяне очищается после слива @autoreleasepool.
Это оставляет очень мало шансов для приложения выжить.
Кэширование не зависит от размера изображения: я пытался рендерить 512x512, а также 4500x512 и 4500x2500 (полноразмерные) фрагменты изображения.

Я использую @autoreleasepool, CFGetRetainCount возвращает 1 для всех CG -объектов перед их очисткой.

Код, который манипулирует данными:

+ (void)render11:(CIImage*)ciImage fromRect:(CGRect)roi toBitmap:(unsigned char*)bitmap {
    @autoreleasepool
    {
        int w = CGRectGetWidth(roi), h = CGRectGetHeight(roi);

        CIContext* ciContext = [CIContext contextWithOptions:nil];
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

        CGContextRef cgContext = CGBitmapContextCreate(bitmap, w, h,
                                                   8, w*4, colorSpace,
                                                   kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);


        CGImageRef cgImage = [ciContext createCGImage:ciImage
                                         fromRect:roi
                                           format:kCIFormatRGBA8
                                       colorSpace:colorSpace
                                         deferred:YES];


        CGContextDrawImage(cgContext, CGRectMake(0, 0, w, h), cgImage);

        assert( CFGetRetainCount(cgImage) == 1 );

        CGColorSpaceRelease(colorSpace);
        CGContextRelease(cgContext);
        CGImageRelease(cgImage);
    }
}


Что я знаю о IOSurface: это из ранее закрытого фреймворка IOSurface.
CIContext имеет функцию render: ... toIOSurface:.
Я создал свой IOSurfaceRef и передал его этой функции, а внутренняя реализация все еще создает свою собственную поверхность и не очищает ее.

Итак, знаете ли вы (или предполагаете):
1. Существуют ли другие способы чтения буфера данных CGImage, кроме CGContextDrawImage / CGDataProviderCopyData?
2. Есть ли способ отключить кеширование при рендере?
3. Почему происходит кэширование?
4. Могу ли я использовать какой-нибудь низкоуровневый (хотя и не приватный) API для очистки системной памяти вручную?

Любые предложения приветствуются.

Ответы [ 2 ]

0 голосов
/ 10 декабря 2018

Чтобы ответить на ваш второй вопрос,

Is there a way to disable caching at render?

установка переменной среды CI_SURFACE_CACHE_CAPACITY в 0 более или менее отключит поверхностный кеш CIContext. Кроме того, вы можете указать пользовательское (приблизительное) ограничение кэша, установив для этой переменной заданное значение в байтах. Например, если задать для CI_SURFACE_CACHE_CAPACITY значение 2147483648, то будет установлено ограничение поверхности кэша в 2 ГБ.

Обратите внимание, что, по-видимому, все CIContext экземпляры процесса совместно используют один поверхностный кэш. По-видимому, невозможно использовать отдельные кэши для CIContext.

0 голосов
/ 09 ноября 2018

Если вам просто нужно манипулировать данными CIImage, возможно, стоит рассмотреть возможность использования CIImageProcessorKernel для помещения данных в вычисления CPU или GPU без их извлечения.

Я заметил, что

[ciContext render: image toBitmap: растровое изображение rowBytes: w * 4 границы: image.extent формат: kCIFormatRGBA8 colorSpace: colorSpace];

Нет такого кеша 90M. Может быть, это то, что вы хотите.

enter image description here

...