sistema - Reducir el uso de memoria en la aplicación iOS sin fugas
liberar espacio sistema iphone (4)
Mi aplicación iOS tiene un alto uso de memoria pero no hay pérdidas de memoria. ¿Cómo puedo reducir el uso de la memoria.
Con los instrumentos, descubrí que mi aplicación alcanza un máximo de 90 MB, antes de que se produzca una advertencia de memoria, y que la otra memoria se haya desasignado, y luego se mantiene entre 55 y 65 MB por el resto de su uso.
Siento que 55-65MB es demasiado alto, ¿verdad?
Desde entonces, los instrumentos no detectaron ninguna fuga. ¿Qué puedo hacer para reducir este uso de memoria?
Revisé el video de la WWDC de este año, pero de las cosas que entendí (esta es mi primera aplicación de iOS), en su mayoría se ocupó de las fugas.
Alguna información posiblemente útil:
VM: ImageIO_GIF_Data 30.35MB Bytes en vivo | 115 Viviendo | 300 Transitoria | 136.12 MB de bytes en general
VM: MappedFile 36.04 MB Bytes en vivo | 16 Viviendo | 11 Transitoria | 36.09 MB de bytes en general
Todo lo demás está bajo 1MB
Mi aplicación descarga alrededor de 30 archivos GIF de Internet, uso SDWebImage y solo guardo las URL de las imágenes, y SDWebImage hace el resto. :PAG
Gracias por adelantado,
Desde un primer temporizador de gestión de memoria de iOS
Gracias una vez más por tu ayuda
Decidí agregar código completo para guardar memoria, si está utilizando archivos GIF, modifique el método de escala de UIImage (lo encontró aquí, un ). Como dijo GangstaGraham en el método SD Image existe método sd_animatedImageByScalingAndCroppingToSize
@interface UIImage (Scaling)
-(UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
-(UIImage*) croppedImageWithRect: (CGRect) rect;
@end
@implementation UIImage (Scaling)
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2.0) {
targetSize.height *= 2.0f;
targetSize.width *= 2.0f;
}
}
NSUInteger width = targetSize.width;
NSUInteger height = targetSize.height;
UIImage *newImage = [self resizedImageWithMinimumSize: CGSizeMake (width, height)];
return [newImage croppedImageWithRect: CGRectMake ((newImage.size.width - width) / 2, (newImage.size.height - height) / 2, width, height)];
}
-(CGImageRef)CGImageWithCorrectOrientation
{
if (self.imageOrientation == UIImageOrientationDown) {
//retaining because caller expects to own the reference
CGImageRetain([self CGImage]);
return [self CGImage];
}
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
if (self.imageOrientation == UIImageOrientationRight) {
CGContextRotateCTM (context, 90 * M_PI/180);
} else if (self.imageOrientation == UIImageOrientationLeft) {
CGContextRotateCTM (context, -90 * M_PI/180);
} else if (self.imageOrientation == UIImageOrientationUp) {
CGContextRotateCTM (context, 180 * M_PI/180);
}
[self drawAtPoint:CGPointMake(0, 0)];
CGImageRef cgImage = CGBitmapContextCreateImage(context);
UIGraphicsEndImageContext();
return cgImage;
}
-(UIImage*)resizedImageWithMinimumSize:(CGSize)size
{
CGImageRef imgRef = [self CGImageWithCorrectOrientation];
CGFloat original_width = CGImageGetWidth(imgRef);
CGFloat original_height = CGImageGetHeight(imgRef);
CGFloat width_ratio = size.width / original_width;
CGFloat height_ratio = size.height / original_height;
CGFloat scale_ratio = width_ratio > height_ratio ? width_ratio : height_ratio;
CGImageRelease(imgRef);
return [self drawImageInBounds: CGRectMake(0, 0, round(original_width * scale_ratio), round(original_height * scale_ratio))];
}
-(UIImage*)drawImageInBounds:(CGRect)bounds
{
UIGraphicsBeginImageContext(bounds.size);
[self drawInRect: bounds];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resizedImage;
}
-(UIImage*)croppedImageWithRect:(CGRect)rect
{
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, self.size.width, self.size.height);
CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
[self drawInRect:drawRect];
UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return subImage;
}
-(UIImage *) resizableImageWithCapInsets2: (UIEdgeInsets) inset
{
if ([self respondsToSelector:@selector(resizableImageWithCapInsets:resizingMode:)])
{
return [self resizableImageWithCapInsets:inset resizingMode:UIImageResizingModeStretch];
}
else
{
float left = (self.size.width-2)/2;//The middle points rarely vary anyway
float top = (self.size.height-2)/2;
return [self stretchableImageWithLeftCapWidth:left topCapHeight:top];
}
}
@end
Y UIImageView:
#import <SDWebImage/SDImageCache.h>
@implementation UIImageView (Scaling)
-(void)setImageWithURL:(NSURL*)url scaleToSize:(BOOL)scale
{
if(url.absoluteString.length < 10) return;
if(!scale){
[self setImageWithURL:url];
return;
}
__block UIImageView* selfimg = self;
__block NSString* prevKey = SPRINTF(@"%@_%ix%i", url.absoluteString, (int)self.frame.size.width, (int)self.frame.size.height);
__block UIImage* prevImage = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^ {
prevImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:prevKey];
if(prevImage){
dispatch_async(dispatch_get_main_queue(), ^ {
[self setImage:prevImage];
});
}else{
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:url options:SDWebImageDownloaderFILOQueueMode progress:nil completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) {
if(error){
[selfimg setImageWithURL:url scaleToSize:scale];
}else{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^ {
prevImage = [image imageByScalingProportionallyToSize:self.frame.size];
if(finished)
[[SDImageCache sharedImageCache] storeImage:prevImage forKey:prevKey];
dispatch_async(dispatch_get_main_queue(), ^ {
[self setImage:prevImage];
});
});
}
}];
}
});
return;
}
-(void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder scaleToSize:(BOOL)scale
{
[self setImage:placeholder];
[self setImageWithURL:url scaleToSize:scale];
}
@end
SDWebImage no hace el resto. Necesita manejar menos imágenes en la memoria, ya que puede: borrar UIImageView cuando no se muestra; utilizar patrones de objetos reutilizables; y, por supuesto, borre las imágenes no visibles (almacenadas en la memoria caché) cuando tenga advertencias de memoria, para esto solo use self.urImage = nil;
Por lo tanto, buen aspecto para guardar la memoria de la aplicación;)
Usted dice que está utilizando una vista de tabla. Aunque las celdas se reutilizan automáticamente, esto hace que sea muy fácil cometer errores y crear demasiados objetos. 1 error común es asignar objetos (por ejemplo, UIImageView) en el método cellForRowAtIndexPath, ya que esto significa que cada vez que una celda se reutiliza, se agrega una nueva UIImageView y se conservan las antiguas. Entonces, vuelva a verificar lo que está pasando en su método cellForRowAtIndexPath.
Yo sugeriría que utilices Instruments y Heapshot Analysis. bbum escribió un artículo al respecto en su blog .
Aquí está una descripción rápida:
- Inicie su aplicación en instrumentos y seleccione la plantilla Asignaciones
- Espere un tiempo después de que su aplicación comience a establecerse
- En Asignaciones, presione
Mark Heap
; Esta es tu línea de base. - Use su aplicación y regrese a la misma pantalla que en # 2. Presione
Mark Heap
nuevo. - Repite eso por algún tiempo.
Si ve un crecimiento constante de la memoria, puede profundizar en los heapshots y ver todos los objetos asignados. Eso debería darle un buen comienzo para reducir su huella de memoria.