2010-04-23 6 views
2

Ok, donc je suis enfin au point où je teste mon iPad sur un iPad réel ...fuites de mémoire iphone et malloc?

Une chose que mon application fait est d'afficher une grande image (2mb) dans une vue défilement. Cela amène l'iPad à recevoir des avertissements de mémoire. Je cours l'application dans les instruments pour vérifier la fuite.

Quand je charge l'image, une fuite est détectée et je vois ce qui suit dans les allocations:

áll Allocations: 83,9 MB Malloc 48.55 MB: 48,55 MB Malloc 34.63 MB: 34,63 MB

Qu'est-ce que j'essaie de comprendre est de savoir comment brancher la fuite évidemment, mais aussi pourquoi une image de 2Mo provoque un malloc de 20x cette taille

Je suis très nouveau à la programmation en obj-c donc je suis sûr que c'est une chose évidente, mais je ne peux pas comprendre. Voici le code:

@interface ChartsViewController : UIViewController <UIScrollViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource> { 
    IBOutlet UIScrollView *scrollView; 
    UIImageView *imageView; 
    NSString *chart; 
    NSString *chartFile; 
    UIPickerView *picker; 
    NSDictionary *chartsDictionary; 
    NSArray *chartTypes; 
    NSArray *charts; 
    IBOutlet UILabel *chartNameLabel; 
    IBOutlet UIActivityIndicatorView *activityIndicator; 



} 

@property (nonatomic, retain) UIScrollView *scrollView; 
@property (nonatomic, retain) UIImageView *imageView; 
@property (nonatomic, retain) NSString *chart; 
@property (nonatomic, retain) NSString *chartFile; 
@property (nonatomic, retain) IBOutlet UIPickerView *picker; 
@property (nonatomic, retain) NSDictionary *chartsDictionary; 
@property (nonatomic, retain) NSArray *chartTypes; 
@property (nonatomic, retain) NSArray *charts; 
@property (nonatomic, retain) IBOutlet UILabel *chartNameLabel; 
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator; 


-(IBAction) chartSelected; 
- (void)alertView:(UIAlertView *)actionSheet 

///////////////////////////////

-(IBAction) chartSelected { 
    [imageView removeFromSuperview]; 
    imageView = nil; 
    chartNameLabel.text = @""; 

    NSInteger chartTypeRow = [picker selectedRowInComponent:kChartTypeComponent]; 
    NSInteger chartRow= [picker selectedRowInComponent:kChartComponent]; 
    chart = [self.charts objectAtIndex:chartRow]; 
    chartFile = [chart stringByReplacingOccurrencesOfString:@" " withString:@"_"]; 


    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, 
                 NSUserDomainMask, YES); 


    NSString *docsPath = [paths objectAtIndex:0]; 
    NSString *tempString = [[NSString alloc]initWithFormat:@"%@/%@.jpg",docsPath,chartFile]; 




    NSData *temp = [NSData dataWithContentsOfFile:tempString]; 

    if (temp != NULL){ 

     temp = nil; 
     [imageView removeFromSuperview]; 
     imageView = nil; 

     UIImageView *tempImage = [[UIImageView alloc]initWithImage:[UIImage imageWithContentsOfFile: tempString]]; 
     [tempString release]; 
     self.imageView = tempImage; 


     scrollView.contentSize = CGSizeMake(imageView.frame.size.width , imageView.frame.size.height); 
     scrollView.maximumZoomScale = 4.0; 
     scrollView.minimumZoomScale = .05; 
     scrollView.clipsToBounds = YES; 
     scrollView.delegate = self; 
     scrollView.zoomScale = .3; 

     [scrollView addSubview:imageView]; 
     [tempImage release]; 
     imageView = nil; 
     chartNameLabel.text = chart; 

    } 

    else { 

     UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Download Chart" 
                 message:@"It appears that you have not yet downloaded this chart. Press OK to download this chart to your iPad. Depending on your internet connection, the download could take several minutes." 
                 delegate:self 
              cancelButtonTitle:@"OK" 
              otherButtonTitles:@"Cancel", nil]; 
     [alert show]; 
     [alert release]; 

    } 

    } 

- (void)dealloc { 

    [imageView release]; 
    [scrollView release]; 
    [chartsDictionary release]; 
    [picker release]; 
    [chartTypes release]; 
    [charts release]; 
    [super dealloc]; 
} 
+0

Manquant le code. –

+0

vous étiez rapide :) il ya maintenant – Brodie

+0

quelqu'un peut-il expliquer pourquoi il alloue 20-30 Mo pour une image de 2-3 Mo? – Brodie

Répondre

2

tempImage fuit toujours.

remplacer la ligne qui dit

imageView = nil; 

avec

[self setImageView: nil]; 

ou

self.imageView = nil; 
2

Beaucoup de fuites dans ce code.

Pour chaque objet créé en utilisant alloc, vous devez le libérer à un moment donné lorsque vous avez fini de l'utiliser.

Les éléments suivants sont divulgués et doivent être libérés

  1. tempString
  2. tempImage
  3. alert

, vous n'avez pas besoin que NSAutoreleasePool, on est créé pour vous par le cadre de cacao avant l'événement qui appelle votre IBAction est appelé et est drainé avec la méthode fin des lavages. Le pool autorelease est également responsable uniquement des éléments qui y ont été placés, y compris tout ce à quoi vous envoyez un message et tous les objets que vous récupérez d'une méthode autre que alloc, new ou l'un avec copy dans le titre.

De même, sachez que définir une variable locale à zéro ne revient pas à la libérer.

Par exemple, la création de l'image doit être

UIImageView *tempImage = [[UIImageView alloc]initWithImage:[UIImage imageWithContentsOfFile: tempString]]; 
self.imageView = tempImage; 
[tempImage release]; 

Edit:

une chose. Lorsque vous accédez à imageview sans utiliser self.imageview, vous accédez directement à l'ivar et non via la propriété. Donc, quand vous faites self.imageview = tempImage, il conserve la vue de l'image comme il se doit, mais quand vous faites imageview = nil il supprime la référence sans libérer la mémoire. C'est une autre fuite. Essayez plutôt self.imageview = nil.Pour ce qui est de la quantité de mémoire, je ne sais pas si elle est liée à l'expansion de l'image en taille réelle (en pixels), et non à sa taille jpg compressée, ou à d'autres données qui fuient avec l'objet UIImageView.

+0

J'ai changé le code et édité mon code ci-dessus, même si le problème n'a pas changé. – Brodie

+0

J'ai édité ma réponse pour inclure une autre fuite. –

0

Les deux lignes suivantes conserveront la UIImageView allouée en tant que tempImage.

self.imageView = tempImage; 
[scrollView addSubview:imageView]; 

ajouter cette ligne après addSubview:

[tempImage release]; 

Vous n'avez pas besoin imageView en tant que membre à moins que vous manipulez plus tard. Si vous le gardez, assurez-vous de le libérer dans dealloc. En général, toutes les propriétés marquées retain doivent être libérées dans dealloc sauf si vous avez des raisons spécifiques de ne pas le faire. Habituellement, je ne fais pas de propriétés ou même de membres pour les vues qui seront dans la hiérarchie de la vue sauf si j'ai besoin de les manipuler, par exemple changer le texte d'un UILabel ou l'état d'un UIButton.

+0

j'ai édité mon code ci-dessus et ai également inclus ma méthode de dealloc. le problème n'a pas changé cependant. Il est dit que j'ai 20-30 Mo alloués alors chaque fois que je charge un nouveau graphique, il ajoute un autre 20-30 Mo – Brodie

3

Vous dites que vous avez une image de 2 Mo. Mais cela signifie un JPG de 2 Mo, non? Donc, quelle est la taille en pixels? Parce que lorsque vous chargez l'image en mémoire, elle doit être décompressée. Et cela signifie que ce sera horizontal resolution * vertical resolution * 8 * 4 (alpha channel) bytes in memory. C'est pourquoi vous voyez 20-30 Mo alloués chaque fois que vous chargez l'image, indépendamment des problèmes de conservation (ce qui signifie simplement que 30 Mo alloués ne seront pas libérés).

+0

Grande explication, merci – Brodie

0

Ce serait une bonne idée de passer à l'ARC. Alternativement, construire avec l'analyseur statique et réparer tous les avertissements qu'il vous donne. C'est très bien à cela.

Il semble que vous utilisiez parfois imageView et parfois self.imageView. Cela indique que votre variable d'instance est imageView et non _imageView. C'est une énorme source de bugs. Si imageView est une propriété (release), self.imageView = nil le libère, mais imageView = nil ne le libère pas. Je suggère fortement de démarrer toutes les variables d'instance avec un trait de soulignement afin que vous y accédiez seulement intentionnellement.