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

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

Во всех случаях, 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 для очистки системной памяти вручную?

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

1 ответ

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

Is there a way to disable caching at render?

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

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

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

Я замечаю что

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

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

введите описание изображения здесь

Другие вопросы по тегам