【问题标题】:NSImage memory leakNSImage 内存泄漏
【发布时间】:2014-07-05 13:39:50
【问题描述】:

首先:我已经在谷歌和 SO 上搜索了解决方案 - 没有一个有效。 我有一个应用程序可以加载当前 iTunes 曲目的插图并显示它;这存储在一个 NSImage 实例中,以及其他一些变量中,在一个类中:

@interface infoBundle : NSObject
 @property (strong) NSImage *track_artwork;
 @property (weak) NSString *track_title;
 @property (weak) NSString *track_album;
 @property (weak) NSString *track_artist;
@end

然后,创建这个类的一个实例:

-(infoBundle*)returnInfoBundle {
 infoBundle* tmpBundle = [[infoBundle alloc]init];
 tmpBundle.track_artwork = [[NSImage alloc]initWithData:[(iTunesArtwork *)[[[iTunes currentTrack] artworks] objectAtIndex:0] rawData]];
 [...]
 return tmpBundle;
}

后来又用了:

-(void)iTunesDidChange {
 infoBundle* tmpBundle = [self returnInfoBundle];
 [...]
 [imageView setImage:tmpBundle.track_artwork];
}

每次调用 iTunesDidChange 会消耗大约 2MB(我猜是封面大小)。

我已经试过了:

  • [tmpBundle 自动释放];
  • [tmpBundle 发布];
  • [tmpBundle dealloc];
  • tmpBundle = nil;

并且,在那之后没有帮助: - 启用 ARC。

=> 尽管对象 (tmpbundle) 应该被删除,但为什么这会占用内存? => 如何实现无泄漏的 NSImage 使用?

感谢任何提示/建议/解决方案:)

【问题讨论】:

  • 下次提示:尝试使用 Instruments 来调试此类性能问题,这对您的应用程序的其他方面更有帮助并且速度更快。
  • tempBundle.track_artwork看起来像是错字?
  • @duci9y 做到了。但是,我发现 Instruments 提供的信息不是很有帮助。确实很详细,但没有帮助。
  • @mikeD 那个错字在哪里? :)
  • 它总是有用的。也许我们可以帮助您解释结果。

标签: objective-c cocoa memory-leaks


【解决方案1】:

问题

如果您在方法上创建对象而不在该方法中释放它,或者当您通过引用将其作为参数传递时必须引用它,则会发生内存泄漏:Passing arguments by value or by reference in objective C

您的问题是您两次创建infoBundle 的实例,当您初始化它的另一个实例时,您将第一个实例留下而没有引用,因此它保留在内存中,并且没有连接删除它(内存泄漏)。

解决方案

为了让你的事情更容易,你应该创建一个对象的实例

@implementation
{
    infoBundle* tmpBundle;
}

在需要的地方使用它

-(infoBundle*)returnInfoBundle 
{
    tmpBundle = [[infoBundle alloc]init];
    tmpBundle.track_artwork = [[NSImage alloc]initWithData:[(iTunesArtwork *)[[[iTunes currentTrack] artworks] objectAtIndex:0] rawData]];
    [...]
    return tmpBundle;
}

-(void)iTunesDidChange 
{
    tmpBundle = [self returnInfoBundle];
    [...]
    [imageView setImage:tmpBundle.track_artwork];
} 

当你完成该对象后,如果你将它添加到 dealloc 方法,dealloc 将自动释放它:

- (void) dealloc
{
    [tmpBundle release];
    tmpBundle = nil;
}

希望对您有所帮助! :)

【讨论】:

    【解决方案2】:

    只需修改这一行:-

      infoBundle* tmpBundle = [[[infoBundle alloc]init]autorelease];
    

    【讨论】:

    • 遗憾的是,我刚刚激活了不允许 [* autorelease] 的 ARC; :(
    • 好的,然后删除自动释放。
    【解决方案3】:

    我无法从您的代码中看出您在 [imageView setImage:tmpbundle.track_artwork]; 中所做的事情;但你可能遇到和我一样的问题。

    我正在使用

    self.imageToDisplay  = [UIImage imageNamed:pictFileName];
    

    并不断泄漏。我切换到了

    self.imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];
    

    然后他们就走了。

    根据 imageNamed 的文档,

    此方法在系统缓存中查找具有 指定名称并返回该对象(如果存在)... 如果您有 只显示一次的图像文件,并希望确保它 没有被添加到系统的缓存中,您应该创建 您的图像使用 imageWithContentsOfFile:。这将使您的 系统图像缓存中的一次性图像,可能会改善 您的应用的内存使用特性。

    听起来您有相同或相似的问题。

    【讨论】:

    • 如何使用 UIImage 开发 Cocoa 应用程序?
    • 如果 Cocoa 不使用 UIImage,那他的问题和我不一样。我的观点是 UIImage:imageNamed 缓存文件并导致泄漏。 UIImage:imagewithContentsOfFile 不会缓存图像,因此不会泄漏。我无法从他的代码中看出他是如何显示图像的,所以我认为他可能有类似的问题。
    • Cocoa 和 Cocoa Touch 是两个不同的东西,傻。
    猜你喜欢
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-15
    • 2011-10-29
    • 1970-01-01
    相关资源
    最近更新 更多