【问题标题】:debugging objective c memory leak with xCode Leaks使用 xCode Leaks 调试目标 c 内存泄漏
【发布时间】:2013-07-12 10:40:54
【问题描述】:

我正在寻找 xCode 4.5 中的内存泄漏和使用 Leaks 工具的第一步。我发现了几个问题并似乎解决了它们,但这个问题让我望而却步。

代码如下:

RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = nm;
[imgInfo->name retain]; // I'm using it outside of this method 

Leaks 在第二行报告泄漏,百分比在 %100 处的“i”旁边。

所以我尝试了两件事:

一,我用 autohrleas 标记了nm,如下所示:

NSString *nm = [[NSString stringWithUTF8String:img->name.c_str()] autorelease];

二,在分配给imgInfo->name 之后,我还尝试在nm 上调用release,所以代码如下所示:

imgInfo->name = nm; 
[imgInfo->name retain]; 
[nm release]; 

但在这两种情况下,当我运行应用程序并调用 [imgInfo->name UTF8String] 时,应用程序都会崩溃并显示 BAD_ACCESS。

我错过了什么?

按照 Rob 的回答进行编辑:

这是 RUBEImageInfo 类:

#import "cocos2d.h"

@interface RUBEImageInfo : NSObject {

@public CCSprite* sprite;               // the image
@public NSString* name;                 // the file the image was loaded from
@public class b2Body* body;             // the body this image is attached to (can be NULL)
@public float scale;                    // a scale of 1 means the image is 1 physics unit high
@public float angle;                    // 'local angle' - relative to the angle of the body
@public CGPoint center;                 // 'local center' - relative to the position of the body
@public float opacity;                  // 0 - 1
@public bool flip;                      // horizontal flip
@public int colorTint[4];               // 0 - 255 RGBA values
}

@end

还有.m:

#import "RUBEImageInfo.h"

@implementation RUBEImageInfo

// Nothing much to see here. Just make sure the body starts as NULL.
-(id)init
{
    if( (self=[super init])) {
        body = NULL;
}
return self;
}

-(void) dealloc {
    [name release];
    [super dealloc];
}

@end

【问题讨论】:

  • 永远不要使用-> 来设置或检索对象中的值。这是完全错误的做法。它很脆弱,会破坏封装,根本不使用。
  • 那么@bbum 你会怎么做呢?
  • 通过点语法或普通方法语法调用setter/getter。

标签: objective-c xcode memory-leaks


【解决方案1】:

几个反应:

  1. 仪器确定了泄漏对象的分配位置,但在这种情况下,此代码可能不是泄漏源。你应该:

    • 确保在deallocRUBEImageInfo 方法中release name;和

    • 另外,如果您要第二次设置 name,请确保在将之前的 name 对象设置为新对象之前将其 release

  2. 如果您使用declared properties 而不是取消引用类实例变量,您的生活会轻松得多。例如,如果 name 被声明为:

    @property (nonatomic, copy) NSString *name; // you could use `retain`, too, but `copy` is safer when dealing with strings
    

    然后您将name 属性设置为:

    RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
    NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
    imgInfo.name = nm;
    // this is no longer needed as the `name` setter will take care of memory semantics
    // [imgInfo->name retain]; // I'm using it outside of this method 
    

    通过使用 setter 访问器方法(即imgInfo.name 的“点语法”),它将处理许多例行内存语义,以释放name 可能已引用的任何先前对象,并且它会做必要的copyretain。显然,RUBEImageInfo方法dealloc仍然需要释放name,但至少简化了RUBEImageInfo对象的name属性的内存语义。

  3. 由于您使用手动引用计数,我鼓励您研究“静态分析器”(通过从 Xcode 的“产品”菜单中选择“分析”来调用)。 Instruments 中的 Leaks 工具会告诉您泄漏了什么,但不会告诉您泄漏发生在哪里;它无法知道;它只能向您显示泄漏对象的分配位置,您必须自己寻找逻辑错误。静态分析器有时可以指出导致泄漏的错误,但更重要的是,向您显示导致泄漏的位置,而不仅仅是泄漏对象最初实例化的位置。在您开始运行 Instruments 之前,您应该从静态分析器中获得一份干净的健康清单。


查看您的代码示例,如果您不打算使用声明的属性(不知道为什么不使用,因为它使生活更轻松,但对每个人来说都是他自己的),我建议您确保初始化所有initrelease 中的所有对象都在 dealloc 中:

@implementation RUBEImageInfo

-(id)init
{
    if ((self=[super init])) {
        body = NULL;
        name = nil;
        sprite = nil;
        // I might initialize other class instance variables here, too, but that's up to you
    }
    return self;
}

-(void) dealloc {
    [name release];
    // shouldn't you release `body` and `sprite`, too?
    [super dealloc];
}

@end

那么设置name 实例变量的代码将确保在设置新对象之前release 之前的对象。因此,初始实例化可能如下所示:

RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = [nm retain]; // retain the new object

但如果你稍后更新它,你应该:

NSString *nm = [NSString stringWithUTF8String:someNewImg->name.c_str()];
[imageInfo->name release];   // release the old one
imgInfo->name = [nm retain]; // retain the new object

【讨论】:

  • 谢谢,罗伯。我尝试在 RUBEImageInfo dealloc 方法中释放名称,但泄漏仍然存在。 (并且分析在那里没有报告任何内容。)我编辑了问题以添加有问题的类。
  • @Eddy 你稍后再设置name 吗?如果是这样,您应该 release 它就像我修改后的答案中所示。如果你省略了这个release,Instruments 会在你最初实例化imgInfo 的地方显示泄露的字符串。如果您没有再次设置 name 实例变量,如我的最终代码示例中所示,那么您必须有其他东西来保留 name 引用的字符串对象。
  • @Eddy 顺便说一句,如果你仍然在泄漏 name,我会暂时在 dealloc 中放置一个断点或 NSLog 语句并确保它被调用(如果没有,泄漏name 是一个更广泛问题的症状,imgInfo 的泄漏),如果它被调用,请检查 [name retainCount](它应该是 1 在你执行 release 之前...如果没有你还有别的东西保留name)。
  • 看起来真正的问题出在我没有编写的 C++ 库中。要么在图书馆,要么在我使用它。我正在继续调查,但无论如何我认为你给了我关于这个问题的所有信息,并推动了我前进。所以谢谢,我很乐意接受答案:)
猜你喜欢
  • 1970-01-01
  • 2013-01-26
  • 1970-01-01
  • 2010-12-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
  • 2021-01-10
相关资源
最近更新 更多