2009-09-15 10 views
5

Ok, ho un mondo di difficoltà nel rintracciare questa perdita di memoria. Quando eseguo questo script non vedo perdite di memoria, ma il mio objectalloc sta salendo. Gli strumenti puntano a CGBitmapContextCreateImage> create_bitmap_data_provider> malloc, questo occupa il 60% del mio objectalloc.iPhone - UIImage Leak, CGBitmapContextCreateImage Leak

Questo codice viene chiamato più volte con un 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]; 

Di seguito è riportata la funzione sfocatura. Credo che il problema objectalloc si trovi qui. Forse ho solo bisogno di un paio di occhi nuovi. Sarebbe bello se qualcuno potesse capirlo. Scusa è un po 'lungo ... Proverò ad accorciarlo.

@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; 
    } 

L'unica cosa che posso pensare che sta tenendo l'objectalloc è questo UIImage * retUIImage = [UIImage imageWithCGImage: CGImage]; ... ma come fare ho comunicato che dopo che è stato restituito? Spero che qualcuno possa aiutare per favore.

+1

ho idea se è legato alla perdita, ma non dovrebbe essere chiamata 'libero (bitmapData)' prima di aver rilasciato il contesto. I blocchi di memoria allocati con 'malloc()' non hanno contatori di ritenzione, quindi se chiami 'free()' viene immediatamente liberato, anche se CGContext lo sta usando. – benzado

+0

Stai mirando a iPhone OS 3.1 o versioni successive? Potrebbe essere un bug nel framework 3.0 o precedente. Se si è su 3.1, non è necessario allocare il bitmapData per 'CGBitmapContextCreate'. Anche '_imageScaledToSize' è una chiamata non documentata. Per favore non usarlo. Alcune persone potrebbero non essere disposte a rispondere alla tua domanda se stai utilizzando chiamate non documentate. – lucius

+0

hey bbullis21 il tuo codice sfocato funziona correttamente sul dispositivo ?? – Leena

risposta

0

Ho visto un comportamento simile e ho letto molti altri post simili. La creazione di un pool autorelease non sembra essere di aiuto. Sembra che la libreria stia perdendo la memoria o la memorizzi in un pool di auto-rilascio di livello superiore, quindi non viene rilasciata fino a tardi. Sospetto che ci sia un bug nel framework ma non posso provarlo.

0

aiuta se effettivamente avvolgere l'assegnazione e introdurvi nel ciclo dell'esistenza struttura piscina,

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]; 

In questo esempio image3.png non sarà rilasciato, ma image1 e image2 sarà.

+0

Non si dovrebbe '-release' dopo' -drain' (che è equivalente a '-release' su runtime non-garbage raccolti) poiché questo causa il doppio rilascio. – kennytm

1

Ottieni clang e gestisci il tuo progetto. Non solo troverà le tue perdite (statiche), ti aiuterà a capire di più sulle regole di conteggio dei riferimenti - almeno lo ha fatto per me.

+1

Oppure esegui "Build & Analyze" in Xcode 3.2 se stai usando Snow Leopard. È clang e fa un buon lavoro di diagramming il flusso di esecuzione che porta al problema. –

0

Alcune idee/pensieri:

Per uno, questo pezzo di codice ha chiaramente problemi dal momento che è possibile liberare bitmapData due volte se il contesto non riesce ad allocare.

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

    CGColorSpaceRelease(colorSpace); 
    free (bitmapData); 

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

Ho anche d'accordo con benzado che bitmapData fino a quando si è fatto con il contesto ... anche se non si blocca, che è sconcertante. forse fortunato

notare che io sono abbastanza sicuro che il fornitore di dati ei bit è si riferisce alla stanno per diventare parte della CGImage tornato da CGImageCreate:

fornitore La fonte dei dati per la bitmap. Per informazioni sui formati di dati supportati, vedere la discussione seguente. Il quarzo conserva questo oggetto; al tuo ritorno, puoi tranquillamente rilasciarlo.

Quindi, ciò significa che fino a quando UIImage che si restituisce non viene rilasciato, non penso che il cgImage o il provider di dati bit andranno via. Quindi, forse il problema è che UIImage non sta andando via tutti?

Perché non usi semplicemente CGBitmapContextCreateImage() per creare l'immagine risultante? Potrebbe essere necessario chiamare CGContextFlush() per forzare il disegno sulla bitmap, ma sembra che si stia eseguendo manualmente la modifica di tutti i pixel, quindi probabilmente non è necessario).

In base alla documentazione vaga, non penso che dovresti essere libero() dal puntatore restituito da CGBitmapContextGetData (ma è un po 'un'ipotesi dovuta alla vaghezza dei documenti).

anche:

non si inizializza srcData, destData & FinalData NULL così il test prima di free() 'ing loro sembra rischioso.

tutto quello che ha detto (e provate alcune di queste cose), abbiamo avuto una perdita nel nostro Mac App a un certo punto, perché in 10.5.6 e precedenti qualche aspetto della CIImage imageWithCGImage, imageByApplyingTransofrm, imageByCroppingToRect, NSBitmapImageRep initWithCIImage o NSBitmapImageRep CGImage trapelato. Questo problema è stato risolto in 10.5.7, quindi è possibile che esista qualcosa di simile nella versione del sistema operativo per iPhone che stai testando.

4

ho usato molte volte al quarzo. Ogni volta che faccio è un incubo. Per quanto ho notato, e ho riempito un bug su Apple l'invio di un progetto come prova di crash, una delle 4 cose è vera:

  1. perdite quarzo come l'inferno
  2. Ci vuole troppo tempo per rilasciare la memoria
  3. utilizza troppa memoria inutilmente o
  4. una combinazione di tutti loro.

una volta ho creato un semplice progetto per dimostrare che. Il progetto aveva un pulsante. Ogni volta che si preme il pulsante, viene aggiunta una piccola immagine (100x100 pixel) allo schermo. L'immagine è stata composta da due strati, l'immagine stessa e un ulteriore strato contenente una linea tratteggiata disegnata attorno al bordo dell'immagine. Questo disegno è stato fatto in quarzo. Premendo 8 volte il pulsante, l'applicazione si è bloccata. Si può dire: premendo il tasto 8 volte e 16 immagini sono state aggiunte alla schermata, questa è la ragione per schiantarsi, giusto?

Invece di disegnare il bordo utilizzando Quartz, ho deciso di avere il bordo pre-disegnato su un PNG e aggiungerlo semplicemente come un livello all'oggetto. Gli stessi due livelli per oggetto creato. Destra?

ho cliccato 100 volte, l'aggiunta di 200 immagini sullo schermo e nessun incidente. La memoria non è mai andata oltre gli 800 Kb. Potrei continuare a cliccare ... l'app è continuata più veloce e veloce. Nessun avviso di memoria, nessun arresto anomalo.

Apple deve esaminare urgentemente il quarzo.

0

Ho avuto lo stesso problema quando utilizzo CGBitmapContextCreate (..) con perdite che si verificano casualmente e aumentando.

Ho risolto questo con la creazione del UIImage dai dati bitmap utilizzando la funzione differente:

Prova:

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

o

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

Se si utilizza la raccolta dei rifiuti, utilizzare CFMakeCollectable (posterFrame).Se si utilizza la gestione della memoria tradizionale, è molto semplice:

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

lanci il CFTypeRef (in questo caso, un CGImageRef) ad un puntatore oggetto Objective-C, inviarlo il messaggio -autorelease, e poi gettato il risultato torna a CGImageRef. Questo modello funziona per (quasi) qualsiasi tipo che sia compatibile con CFRetain() e CFRelease().

How to Autorelease a CGImageRef?

Problemi correlati