Есть ли способ прочитать данные из 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М нет. Может быть, это то, что вы хотите.