【问题标题】:How come my app seems to be holding an image in memory?为什么我的应用程序似乎在内存中保存了图像?
【发布时间】:2011-04-03 23:48:59
【问题描述】:

我有一个带有非常大图像的 IntroViewController,这使我的应用程序的内存增加了大约 1.5MB。图像设置在 View Controller 的 NIB 中的 UIImageView 上。

介绍完成后,我在 IntroViewController 上调用 release,然后它在自身上成功调用 dealloc 并在大型 UIImageView 上调用 release。然而,我在 Instruments 中的记忆似乎并没有再次下降。我可以通过简单地将图像重命名为NIB中的UIImageView来测试内存差异,这样它就找不到任何东西了,然后内存下降了大约1.5MB。

那为什么我没有找回记忆呢?有什么我遗漏的东西阻止了 UIImageView 被正确地释放吗?

谢谢,

:-乔

------- 添加:代码 ------

#import <UIKit/UIKit.h>

@class AppDelegate_iPhone;

@interface IntroViewController : UIViewController
{
    AppDelegate_iPhone *appDelegate;

    UIImageView *wheelImageView;
    UIView *copyOverlayView;
}

@property (nonatomic, retain) IBOutlet UIImageView *wheelImageView;
@property (nonatomic, retain) IBOutlet UIView *copyOverlayView;

- (void)startAnimation;

@end

@implementation IntroViewController

@synthesize wheelImageView, copyOverlayView;

- (void)viewDidLoad
{
    [super viewDidLoad];
    appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
    [self startAnimation];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [self.wheelImageView removeFromSuperview];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.wheelImageView.image = nil;
    appDelegate = nil;
}

- (void)dealloc
{
     [wheelImageView release];
     [copyOverlayView release];

    [super dealloc];
}

- (void)startAnimation
{
    self.wheelImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
    [UIView beginAnimations:@"wheelScale" context:nil];
    [UIView setAnimationDuration:2.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(wheelScaleDidFinish)];
    self.wheelImageView.transform = CGAffineTransformMakeScale(1.0, 1.0);
    [UIView commitAnimations];

    [UIView beginAnimations:@"copyOverlayFade" context:nil];
    [UIView setAnimationDuration:1.0];
    [UIView setAnimationDelay:1.0];
    self.copyOverlayView.alpha = 0;
    [UIView commitAnimations];
}

- (void)wheelScaleDidFinish
{
    [appDelegate introAnimationFinished];
}

@end

---- 编辑

有人可以帮忙吗?我被难住了,这导致我的应用程序由于内存过高而在 iPhone 上崩溃 :( 无法弄清楚如何摆脱愚蠢的图像!Grrrr ...

【问题讨论】:

    标签: objective-c iphone memory-management memory-leaks


    【解决方案1】:

    好的,我找到了解决方案,但我对此感到非常惊讶!

    我不仅必须从 IB 中取出 UIImageView 并动态创建它,而且还必须避免使用方便的方法来加载图像。而不是:

    wheelImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"wheel-intro.png"];
    [self.view addSubview:self.wheelImageView];
    [wheelImageView release];
    

    我不得不使用:

    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"wheel-intro" ofType:@"png"];
    wheelImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
    wheelImageView = [[UIImageView alloc] initWithImage:wheelImage];
    [wheelImage release];
    [self.view addSubview:self.wheelImageView];
    [wheelImageView release];
    

    现在,当我在 viewDidDisappear 处理程序中执行 [wheelImageView removeFromSuperview] 时,一切都会正确清理。

    我觉得非常奇怪的是,将图像放入 Interface Builder 在内存管理中与在 XCode 中使用便捷方法相同。而且都不能正常工作!自我注意:停止使用方便的方法...

    【讨论】:

    • 原因是 UIImage imageNamed: 和朋友们维护了一个图片缓存。在压力下系统会释放内存。
    • 那么虽然有autorelease,但有些对象有自己的缓存?这是一个鲜为人知的事实,谢谢。但是,你说在压力下系统会释放内存,但实际上对我来说,手机因内存不足而崩溃,而 Leaks 仍然显示缓存的图像!
    【解决方案2】:

    UIImageView 正在发布,但您确定在其他地方没有幻影保留吗?如果我是你,我会尝试追踪它的保留和发布。您可以使用时髦的调试器技巧、malloc_history 等工具来做到这一点,也可以简单地创建 UIImageView 的子类:

    @interface DebugImageView @end
    @implementation DebugImageView
      - (id) retain {
        NSLog(@"retained");
        return [super retain];
      }
    
      - (void) release {
        NSLog(@"release");
        [super release];
      }
    
      - (void) dealloc {
        NSLog(@"dealloc");
        [super dealloc];
      }
    

    只需将 IB 中的 UIImageView 对象的类更改为 DebugImageView,就可以了。您还可以在这些上放置断点以查看它们被调用的位置,或者只是调用我有日志记录语句的backtrace()

    如果对象实际上正在被删除,那么您的内存增加可能并不严重,并且很可能是由于延迟驱逐的大型可重用缓冲区对象或堆碎片。 1.5MB 对于这类东西来说似乎有点高,所以我怀疑它是一个过度保留。

    【讨论】:

    • 谢谢 - 我试过了,我看到很多痕迹!不过,它似乎确实在最后调用了“dealloc”。是否有可能因为它是 UIView 动画的一部分,所以它会保留图像?我是否需要释放或取消委派 UIView 动画序列?
    • PS 在泄漏中,我可以看到它仍然存在 - 我有一个 1.39MB 的 Malloc 和负责的库 ImageIO...
    • 可以想象图像可以被复制到支持 CALayer 的缓冲区中出去。另外,您使用的是什么 init 方法,您是否有机会保留用于创建图像的缓冲区(如 NSData)?
    • 我没有直接使用 CALayer,但我正在创建带有 ID 名称的 UIView 动画......这可能是持有参考吗?奇怪的是我看到了“dealloc”跟踪。无论如何,我已将所有代码发布到上面的 ViewController :-) 谢谢!
    猜你喜欢
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多