2009-09-15 15 views
5

ठीक है मैं कठिनाई यह स्मृति रिसाव पर नज़र रखने की एक दुनिया हो रहा है। इस स्क्रिप्ट को चलाने पर मुझे कोई मेमोरी लीक नहीं दिखाई दे रही है, लेकिन मेरा ऑब्जेक्टॉल चढ़ रहा है। CGBitmapContextCreateImage को उपकरण अंक> create_bitmap_data_provider> malloc, इस मेरे objectalloc का 60% लेता है।iPhone - UIImage रिसाव, CGBitmapContextCreateImage रिसाव

इस कोड को एक NSTimer के साथ कई बार कहा जाता है।

//GET IMAGE FROM RESOURCE DIR 
    NSString * fileLocation = [[NSBundle mainBundle] pathForResource:imgMain ofType:@"jpg"]; 
    NSData * imageData = [NSData dataWithContentsOfFile:fileLocation]; 
    UIImage * blurMe = [UIImage imageWithData:imageData]; 

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    UIImage * scaledImage = [blurMe _imageScaledToSize:CGSizeMake(blurMe.size.width/dblBlurLevel, blurMe.size.width/dblBlurLevel) interpolationQuality:3.0]; 
    UIImage * labelImage = [scaledImage _imageScaledToSize:blurMe.size interpolationQuality:3.0]; 
    UIImage * imageCopy = [[UIImage alloc] initWithCGImage:labelImage.CGImage]; 

    [pool drain]; // deallocates scaledImage and labelImage 

    imgView.image = imageCopy; 
    [imageCopy release]; 

नीचे धुंधला कार्य है। मेरा मानना ​​है कि ऑब्जेक्टॉलोक इश्यू यहां स्थित है। शायद मुझे ताजा आंखों की एक जोड़ी चाहिए। अगर कोई इसे समझ सके तो अच्छा होगा। क्षमा करें यह बहुत लंबा है ... मैं कोशिश करूँगा और इसे छोटा कर दूंगा।

@implementation UIImage(Blur) 
    - (UIImage *)blurredCopy:(int)pixelRadius 
    { 
     //VARS 
     unsigned char *srcData, *destData, *finalData; 
     CGContextRef context = NULL; 
     CGColorSpaceRef colorSpace; 
     void *   bitmapData; 
     int    bitmapByteCount; 
     int    bitmapBytesPerRow; 

     //IMAGE SIZE 
     size_t pixelsWide = CGImageGetWidth(self.CGImage); 
     size_t pixelsHigh = CGImageGetHeight(self.CGImage); 
     bitmapBytesPerRow = (pixelsWide * 4); 
     bitmapByteCount  = (bitmapBytesPerRow * pixelsHigh); 

     colorSpace = CGColorSpaceCreateDeviceRGB(); 
     if (colorSpace == NULL) { return NULL; } 

     bitmapData = malloc(bitmapByteCount); 
     if (bitmapData == NULL) { CGColorSpaceRelease(colorSpace); } 

     context = CGBitmapContextCreate (bitmapData, 
         pixelsWide, 
         pixelsHigh, 
         8,  
         bitmapBytesPerRow, 
         colorSpace, 
         kCGImageAlphaPremultipliedFirst); 
     if (context == NULL) { free (bitmapData); } 

     CGColorSpaceRelease(colorSpace); 
     free (bitmapData); 

     if (context == NULL) { return NULL; } 

     //PREPARE BLUR 
     size_t width = CGBitmapContextGetWidth(context); 
     size_t height = CGBitmapContextGetHeight(context); 
     size_t bpr = CGBitmapContextGetBytesPerRow(context); 
     size_t bpp = (CGBitmapContextGetBitsPerPixel(context)/8); 
     CGRect rect = {{0,0},{width,height}}; 

     CGContextDrawImage(context, rect, self.CGImage); 

     // Now we can get a pointer to the image data associated with the bitmap 
     // context. 
     srcData = (unsigned char *)CGBitmapContextGetData (context); 
     if (srcData != NULL) 
     { 

      size_t dataSize = bpr * height; 
      finalData = malloc(dataSize); 
      destData = malloc(dataSize); 
      memcpy(finalData, srcData, dataSize); 
      memcpy(destData, srcData, dataSize); 

      int sums[5]; 
      int i, x, y, k; 
      int gauss_sum=0; 
      int radius = pixelRadius * 2 + 1; 
      int *gauss_fact = malloc(radius * sizeof(int)); 

      for (i = 0; i < pixelRadius; i++) 
      { 
      .....blah blah blah... 
       THIS IS JUST LONG CODE THE CREATES INT FIGURES 
       ........blah blah blah...... 
       } 


      if (gauss_fact) { free(gauss_fact); } 
     } 

     size_t bitmapByteCount2 = bpr * height; 
     //CREATE DATA PROVIDER 
     CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, srcData, bitmapByteCount2, NULL); 

     //CREATE IMAGE 
     CGImageRef cgImage = CGImageCreate(
           width, 
           height, 
           CGBitmapContextGetBitsPerComponent(context), 
           CGBitmapContextGetBitsPerPixel(context), 
           CGBitmapContextGetBytesPerRow(context), 
           CGBitmapContextGetColorSpace(context), 
           CGBitmapContextGetBitmapInfo(context), 
           dataProvider, 
           NULL, 
           true, 
           kCGRenderingIntentDefault 
            ); 

     //RELEASE INFORMATION 
     CGDataProviderRelease(dataProvider); 
     CGContextRelease(context); 

     if (destData) { free(destData); } 
     if (finalData) { free(finalData); } 
     if (srcData) { free(srcData); } 


     UIImage *retUIImage = [UIImage imageWithCGImage:cgImage]; 
     CGImageRelease(cgImage); 

     return retUIImage; 
    } 

केवल एक चीज मैं उस बारे में सोच सकते objectalloc को पकड़े रहा है इस UIImage * retUIImage = [UIImage imageWithCGImage: cgImage]; ... लेकिन कैसे करना है मैं जारी करने के बाद यह वापस आ गया है? उम्मीद है कि कोई मदद कर सकता है।

+1

मैं अगर यह रिसाव से संबंधित है पता नहीं है, लेकिन आप 'मुक्त (BitmapData) नहीं बुला जाना चाहिए' आप संदर्भ जारी किया है पहले। 'Malloc() 'के साथ आवंटित स्मृति के ब्लॉक काउंटर बनाए रखते नहीं हैं, इसलिए यदि आप' फ्री() 'कहते हैं तो इसे तुरंत मुक्त कर दिया जाता है, भले ही CGContext इसका उपयोग कर रहा हो। – benzado

+0

क्या आप आईफोन ओएस 3.1 या उच्चतर को लक्षित कर रहे हैं? यह 3.0 या पहले के ढांचे में एक बग हो सकता है। यदि आप 3.1 पर हैं, तो आपको 'CGBitmapContextCreate' के लिए बिटमैपडेटा आवंटित करने की आवश्यकता नहीं है। इसके अलावा '_imageScaledToSize' एक अनियंत्रित कॉल है। कृपया इसका इस्तेमाल न करें। यदि आप अनियंत्रित कॉल का उपयोग कर रहे हैं तो कुछ लोग आपके प्रश्न का उत्तर देने के इच्छुक नहीं हो सकते हैं। – lucius

+0

हे bbullis21 क्या आपका ब्लर कोड डिवाइस पर ठीक काम कर रहा है ?? – Leena

उत्तर

0

मैं समान व्यवहार देखा और कई अन्य समान पदों पढ़ा है। एक ऑटोरेलीज पूल बनाना मदद नहीं करता है। ऐसा लगता है कि पुस्तकालय या तो स्मृति लीक या एक उच्च स्तर स्वत: रिहाई पूल में भंडारण तो बहुत देर तक जारी नहीं हो रही है की तरह। मुझे संदेह है कि ढांचे में एक बग है लेकिन यह साबित नहीं कर सकता है।

0

यह मदद करता है अगर आप वास्तव में छवि आवंटन लपेट और पूल वस्तु अस्तित्व चक्र में जारी,

pool = [[NSAutoreleasePool alloc] init]; 

[imageView setImage: [UIImage imageNamed:"image1.png"]]; 
... 
[imageView setImage: [UIImage imageNamed:"image2.png"]]; 
... 
[imageView setImage: [UIImage imageNamed:"image3.png"]]; 
.... 
[pool drain]; 
[pool release]; 

इस उदाहरण image3.png में नहीं जारी किया जाएगा, लेकिन Image1 और Image2 हो जाएगा।

+0

आपको '-्रेन' के बाद '-release' नहीं करना चाहिए (जो गैर-कचरा एकत्रित रनटाइम्स पर' -release' के बराबर है) क्योंकि इससे डबल रिलीज़ होता है। – kennytm

1

clang प्राप्त करें और इसके माध्यम से अपनी परियोजना चलाएं। कम से कम यह मेरे लिए किया था - यह न केवल आपके (स्थिर) लीक मिलेगा, यह आप संदर्भ गिनती नियमों के बारे में अधिक समझने में मदद मिलेगी।

+1

या यदि आप हिम तेंदुए चला रहे हैं तो एक्सकोड 3.2 में "बिल्ड करें और विश्लेषण करें" चलाएं। यह झगड़ा है और समस्या के कारण निष्पादन के प्रवाह को चित्रित करने का एक अच्छा काम करता है। –

0

कुछ विचार/विचार:

एक के लिए, कोड के इस खंड स्पष्ट रूप से समस्या है आप BitmapData दो बार मुक्त कर सकता है, क्योंकि अगर संदर्भ आवंटित करने के लिए विफल रहता है।

if (context == NULL) { free (bitmapData); } 

    CGColorSpaceRelease(colorSpace); 
    free (bitmapData); 

    if (context == NULL) { return NULL; } 

मैं भी benzado कि आप BitmapData जब तक आप संदर्भ ... के साथ किया जाता है, हालांकि यह दुर्घटनाग्रस्त नहीं है जो puzzling है के साथ सहमत हैं। शायद भाग्यशाली CGImageCreate से लौटे cgImage का हिस्सा बनने के लिए जा रहे हैं करने के लिए

ध्यान दें कि मैं यकीन है कि डेटा प्रदाता और बिट्स है हूँ संदर्भित करता है:

प्रदाता बिटमैप के लिए आंकड़ों का स्रोत। समर्थित डेटा प्रारूपों के बारे में जानकारी के लिए, नीचे दी गई चर्चा देखें। क्वार्ट्ज इस वस्तु को बरकरार रखता है; बदले में, आप इसे सुरक्षित रूप से रिलीज़ कर सकते हैं।

तो, इसका मतलब है कि जब तक आप वापस आने वाले यूआईएममेज को जारी नहीं करते हैं, मुझे नहीं लगता कि सीजीआईमेज या बिट्स डेटा प्रदाता दूर जा रहे हैं। तो, शायद मुद्दा यह है कि UIImage हर जा रहा नहीं है?

परिणामस्वरूप छवि बनाने के लिए आप केवल CGBitmapContextCreateImage() का उपयोग क्यों नहीं कर रहे हैं? (आपको बिटमैप पर ड्राइंग को मजबूर करने के लिए CGContextFlush() को कॉल करने की आवश्यकता हो सकती है, लेकिन ऐसा लगता है कि आप मैन्युअल रूप से बदल रहे सभी पिक्सेल कर रहे हैं, इसलिए संभवतः आवश्यक नहीं है)।

अस्पष्ट प्रलेखन के आधार पर, मैं सूचक CGBitmapContextGetData द्वारा दिया ing नहीं लगता कि आप मुक्त किया जाना चाहिए() '(लेकिन यह है कि किए गए दस्तावेज़ों की अस्पष्टता के कारण एक अनुमान का एक सा है)।

भी

:

आप srcData आरंभ नहीं कर रहे हैं, destData & finalData ing उन्हें जोखिम भरा लगता है तो अपने परीक्षण से पहले मुक्त करने के लिए शून्य पर() '।

कि सभी ने कहा कि (और उन चीजों में से कुछ की कोशिश करते हैं), हम 10.5.6 में क्योंकि एक बिंदु पर हमारे मैक App में एक रिसाव था और CIImage imageWithCGImage, imageByApplyingTransofrm, imageByCroppingToRect, NSBitmapImageRep initWithCIImage या NSBitmapImageRep CGImage के कुछ पहलू पहले लीक। यह 10.5.7 में तय किया गया था, इसलिए यह संभव है कि आईफोन ओएस संस्करण में कुछ ऐसा ही मौजूद है जिसका आप परीक्षण कर रहे हैं।

0

असल में अगर मुझे याद है [UIImage imageNamed] अपने स्वयं के कैश बनाता है, जो आपके नियंत्रण से बाहर है। वह स्मृति उपयोग के लिए जिम्मेदार होगा जो आप देख रहे हैं। आप यहां और अधिक पढ़ सकते हैं - http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/

4

मैंने कई बार क्वार्ट्ज का उपयोग किया है। हर बार जब मैं एक दुःस्वप्न करता हूं। जहां तक ​​मैंने देखा है, और मैं दुर्घटना के सबूत के रूप में एक परियोजना भेजने एप्पल पर एक बग से जमा की है, 4 चीजों में से एक सत्य है: नरक के रूप में

  1. क्वार्ट्ज लीक
  2. यह भी स्मृति जारी करने के लिए समय लगता है
  3. यह बहुत अधिक स्मृति का उपयोग करता है अनावश्यक रूप से या
  4. उन सभी का संयोजन।

मैंने इसे साबित करने के लिए एक साधारण परियोजना बनाई है। परियोजना में एक बटन था। प्रत्येक बार जब बटन दबाया गया था तो स्क्रीन पर एक छोटी छवि (100x100 पिक्सल) जोड़ दी गई थी। छवि दो परतों, छवि स्वयं और छवि सीमा के चारों ओर खींची गई एक धराशायी रेखा वाली एक अतिरिक्त परत द्वारा रचित थी। यह चित्र क्वार्ट्ज में किया गया था। बटन को 8 बार दबाकर एप्लिकेशन क्रैश हो गया। आप कह सकते हैं: बटन को 8 बार और 16 छवियों को दबाकर स्क्रीन में जोड़ा गया था, यही कारण है कि दुर्घटनाग्रस्त होने का कारण है, है ना?

क्वार्ट्ज का उपयोग करके सीमा खींचने के बजाय, मैंने एक पीएनजी पर सीमा पूर्व-ड्रॉ रखने का फैसला किया और बस इसे ऑब्जेक्ट में एक परत के रूप में जोड़ें। प्रति ऑब्जेक्ट की समान दो परतें बनाई गईं। सही?

मैंने 100 बार क्लिक किया, स्क्रीन पर 200 छवियां और कोई क्रैश नहीं जोड़ा। स्मृति 800 Kb से ऊपर कभी नहीं चला गया। मैं क्लिक करना जारी रख सकता था ... ऐप ने स्नैपियर और तेज़ जारी रखा। कोई स्मृति चेतावनी, कोई दुर्घटना नहीं।

ऐप्पल को तुरंत क्वार्ट्ज की समीक्षा करनी है।

0

मुझे सीजीबीआईटीएमएपी कॉन्टेक्स्टक्रेट (..) का उपयोग करते समय यादृच्छिक रूप से होने और निर्माण के साथ एक ही समस्या थी।

प्रयास करें:

CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); 

या

provider = CGDataProviderCreateWithData((void *)pixelBuffer, sourceBaseAddr, sourceRowBytes * height, ReleaseCVPixelBufferFunction); 


CGImageRef imageRef = CGImageCreate(cvMat.cols,          // Width 
            cvMat.rows,          // Height 
            8,            // Bits per component 
            8 * cvMat.elemSize(),       // Bits per pixel 
            cvMat.step,          // Bytes per row 
            colorSpace,          // Colorspace 
            kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags 
            provider,          // CGDataProviderRef 
            NULL,           // Decode 
            false,           // Should interpolate 
            kCGRenderingIntentDefault);      // Intent 
0

आप कचरा संग्रहण का उपयोग कर रहे हैं, तो का उपयोग CFMakeCollectable

मैं बिटमैप डेटा से UIImage बनाने अलग समारोह का उपयोग करके इस हल (posterFrame)।आप पारंपरिक स्मृति प्रबंधन उपयोग कर रहे हैं, यह बहुत सीधा है:

return (CGImageRef)[(id)posterFrame autorelease]; 

आप CFTypeRef डाली एक ऑब्जेक्टिव-सी वस्तु सूचक (इस मामले में, एक CGImageRef में), यह -autorelease संदेश भेजते हैं, और उसके बाद डाली परिणाम CGImageRef पर वापस। यह पैटर्न (लगभग) किसी भी प्रकार के लिए काम करता है जो CFRetain() और CFRelease() के साथ संगत है।

How to Autorelease a CGImageRef?