2015-09-11 12 views
6

मैंने केवल आईओएस 9 पर इस व्यवहार को देखा है; आईओएस 8 सही ढंग से काम करता है।क्यों CIContext.createCGImage मेमोरी रिसाव का कारण बनता है?

मुझे संदेह है कि यह एसडीके पर एक बग हो सकता है, और मैंने ऐप्पल (22644754) को एक रडार खोला है, लेकिन मुझे यह बहुत अजीब लगता है कि मुझे यह महसूस हो रहा है कि मुझे कॉल या एक कदम याद आ रहा है रिसाव से बचें।

मैंने जो देखा है वह है कि हर बार CIContext.createCGImage कहा जाता है, स्मृति उपयोग में वृद्धि होती है। मुश्किल हिस्सा यह है कि ऐप के बाहर स्मृति वृद्धि होती है।

यदि आप एक्सकोड से "मेमोरी रिपोर्ट" देखते हैं, तो "अन्य प्रक्रियाओं" खंड पर स्मृति वृद्धि दिखाई दे रही है।

सबसे पहले मैं एक CIContext एक EAGLContext द्वारा समर्थित बनाने के लिए::

मूल रूप से, मैं क्या पैदा करने के लिए समस्या निम्नलिखित है (मैं अत्यंत आवश्यक होता भागों रिसाव पुन: पेश करने के लिए कोड को सरल बनाया है)

let glContext = EAGLContext(API: .OpenGLES2)! 
let ciContext = CIContext(EAGLContext: glContext, options: [kCIContextOutputColorSpace : NSNull()]) 

फिर, मैं एक छवि निम्नलिखित का उपयोग कर प्रस्तुत करना:

let input = CIImage(image: UIImage(named: "DummyImage")!)! 
ciContext.createCGImage(input, fromRect: input.extent) 

DummyImage सिर्फ एक नमूना छवि फ़ाइल है। रिसाव सीधे इस छवि के आकार से जुड़ा हुआ है, इसलिए समस्या को और अधिक ध्यान देने योग्य बनाने के लिए एक बड़े का उपयोग करना सबसे अच्छा है।

जैसा कि आप देख सकते हैं, मैं किसी भी सीआईफ़िल्टर का उपयोग नहीं कर रहा हूं (उनका उपयोग करके एक ही परिणाम होता है), और मैं परिणामस्वरूप छवि को कैप्चर नहीं कर रहा हूं (भले ही मैंने इसे कैप्चर किया हो, मैं ऑब्जेक्ट्स के रूप में CGImageRelease का उपयोग नहीं कर सका स्वचालित रूप से प्रबंधित होते हैं)।

यदि रेंडर कोड पर्याप्त बार निष्पादित किया जाता है, तो स्मृति इतनी बढ़ जाएगी कि चल रहे ऐप्स मारे जाएंगे।

एक दिलचस्प अवलोकन यह है कि सीआईसीएन्टेक्स्ट को नष्ट करने से कोई फर्क नहीं पड़ता है, लेकिन ईएजीएलकॉन्टेक्स्ट को नष्ट करने से लिया गया स्मृति वापस आ जाता है। इससे मुझे लगता है कि ओपनजीएल पक्ष पर रिसाव हो रहा है।

क्या मुझे अपने कोड में कुछ भी याद आ रहा है जो रिसाव का कारण बन सकता है? क्या EAGLContext द्वारा ली गई मेमोरी को खाली करने के लिए मैं कोई कॉल कर सकता हूं? (इसे हर समय पुनर्निर्माण करना एक विकल्प नहीं है क्योंकि यह एक महंगा ऑपरेशन है)।


मैं समस्या को ठीक करने के लिए एक सरल परियोजना बनाया है। आप इसे पा सकते हैं:

https://www.dropbox.com/s/zm19u8rmujv6jet/EAGLContextLeakDemo.zip?dl=0

को चरणबद्ध कर रहे हैं:

  1. ओपन और एक डिवाइस पर संलग्न प्रोजेक्ट को चलाने।
  2. एक्सकोड पर "मेमोरी रिपोर्ट" स्क्रीन का निरीक्षण करें। "उपयोग तुलना" पाई चार्ट के "अन्य प्रक्रियाओं" भाग पर वृद्धि देखी जाएगी।
  3. ऐप तीन बटन प्रस्तुत करता है। उनमें से प्रत्येक createCGImage कमांड को निश्चित समय (बटन लेबल पर दिखाया गया) निष्पादित करेगा।
  4. किसी भी बटन पर टैप करने से "अन्य प्रक्रियाओं" की स्मृति उपयोग में वृद्धि होगी। कई createCGImage कॉल करने के बाद यह अधिक ध्यान देने योग्य हो सकता है।
  5. 100 रेंडर बटन पर टैप करने से प्रभाव स्पष्ट रूप से दिखाई देगा।
  6. जब स्मृति वृद्धि अत्यधिक होती है, तो ऐप क्रैश हो जाएगा।

उत्तर

0

यह आईओएस 9. पर एक बग के रूप में पुष्टि की गई है मुद्दा आईओएस 9.1 बीटा से शुरू होने वाले हल किया गया है 3.

कोड तैनात मूल प्रश्न में सही है। आईओएस 9 से पहले के संस्करणों या आईओएस 9.1 से शुरू होने वाले संस्करणों पर रिसाव को रोकने के लिए आवश्यक कोई संशोधन नहीं है। बीटा 3.

1

जिस तरह से मैंने इसे हल किया है, संदर्भ को एक बफर में प्रस्तुत करना था और फिर इसे जेपीजी के रूप में फाइल करना था। मुझे आगे देखना होगा कि पुराने जीओ आईओएस उपकरणों पर इस प्रवाह को कैसे अनुकूलित किया जाए, लेकिन ऐसा लगता है कि createCGImage की तुलना में यह अच्छी तरह से काम करता है। यह कोड सीआईएममेज को जेपीईजी या बिटमैप एनएसडीटा में बदलने के लिए भी उपयोगी है। पूर्ण नमूना कोड यहाँ देखा जा सकता:

https://github.com/mmackh/IPDFCameraViewController

static CIContext *ctx = nil; 

if (!ctx) 
{ 
    ctx = [CIContext contextWithOptions:@{kCIContextWorkingColorSpace:[NSNull null]}]; 
} 

CGSize bounds = enhancedImage.extent.size; 
int bytesPerPixel = 8; 
uint rowBytes = bytesPerPixel * bounds.width; 
uint totalBytes = rowBytes * bounds.height; 
uint8_t *byteBuffer = malloc(totalBytes); 

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

[ctx render:enhancedImage toBitmap:byteBuffer rowBytes:rowBytes bounds:enhancedImage.extent format:kCIFormatRGBA8 colorSpace:colorSpace]; 

CGContextRef bitmapContext = CGBitmapContextCreate(byteBuffer,bounds.width,bounds.height,bytesPerPixel,rowBytes,colorSpace,kCGImageAlphaNoneSkipLast); 

CGImageRef imgRef = CGBitmapContextCreateImage(bitmapContext); 

CGColorSpaceRelease(colorSpace); 
CGContextRelease(bitmapContext); 
free(byteBuffer); 

if (imgRef == NULL) { goto release; } 


CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:filePath]; 
CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypeJPEG, 1, NULL); 
CGImageDestinationAddImage(destination, imgRef, nil); 
CGImageDestinationFinalize(destination); 
CFRelease(destination); 

success = YES; 

goto release; 

release : 
{ 
    CFRelease(imgRef); 

    if (success) 
    { 
     //completionHandler(filePath); 
    } 

    dispatch_resume(_captureQueue); 
} 
+0

क्यों 'बाइट्सपीरपीक्सेल = 8'? 'KCIFormatRGBA8' एक 4 बाइट प्रति पिक्सेल प्रारूप नहीं है? –

संबंधित मुद्दे