【问题标题】:iPhone: memory leak on autoreleased object?iPhone:自动释放对象的内存泄漏?
【发布时间】:2011-04-27 11:13:09
【问题描述】:

我正在使用 XMLParser 类,它包含一个带有 XMLElement 对象的数组。正在使用自动释放操作分配 XMLElement。但是,由于某种原因,我在这条线上遇到了内存泄漏(使用仪器):

self.currentElement = [[[XMLElement alloc] init] autorelease];

我还在调用者类中发布了 XMLParser 对象。我在下面的 XMLParser 源代码中突出显示了“有问题”的行作为注释。

我真的想尽一切办法来修复它,但不幸的是我完全不明白为什么会发生这种情况。任何帮助表示赞赏!

非常感谢!

// --- XMLElement

#import <Foundation/Foundation.h>


@interface XMLElement : NSObject {
     NSDictionary *attributes;
     NSMutableArray *children;
     NSString *textValue;
     NSString *tagName;
     XMLElement *parentElement;
}

-(id) init;
-(void) addChild:(XMLElement*) child;

@property(nonatomic, retain) NSDictionary *attributes;
@property(nonatomic, retain) NSMutableArray *children;
@property(nonatomic, retain) NSString *textValue;
@property(nonatomic, retain) NSString *tagName;
@property(nonatomic, retain) XMLElement *parentElement;

@end


#import "XMLElement.h"


@implementation XMLElement

@synthesize attributes, children, textValue, parentElement, tagName;

-(id)init {
     if(self = [super init]) {
          children = [[NSMutableArray alloc] init];
     }
     return self;
}

-(void) addChild:(XMLElement*) child{
     [self.children addObject:child];
}

- (void)dealloc {
     [attributes release];
     [children release];
     [textValue release];
     [tagName release];
     [parentElement release];
    [super dealloc];
}

@end





// --- XMLParser

#import <Foundation/Foundation.h>
#import "XMLElement.h"

@interface XMLParser : NSObject<NSXMLParserDelegate> {
     XMLElement *currentElement;
     XMLElement *currentParentElement;
     NSMutableString *currentElementValue;
}

- (BOOL)parseData: (NSData*) dataToParse;

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
     attributes:(NSDictionary *)attributeDict;

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;

@property (nonatomic, retain) XMLElement *currentParentElement;
@property (nonatomic, retain) XMLElement *currentElement;
@property (nonatomic, retain) NSMutableString *currentElementValue;

@end


#import "XMLParser.h"


@implementation XMLParser

@synthesize currentElementValue, currentElement, currentParentElement;

- (BOOL)parseData: (NSData*) dataToParse {

     NSXMLParser *parser = [[NSXMLParser alloc] initWithData:dataToParse];
     [parser setDelegate:self];
     BOOL success = [parser parse];
     [parser release];
     return success;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
     attributes:(NSDictionary *)attributeDict{
     if(currentElement){
          self.currentParentElement = currentElement;
     }


     // ------------------------------------------------------------
     // Instruments is marking this line as source of the leak with 90%
     self.currentElement = [[[XMLElement alloc] init] autorelease];
     // --------

     currentElement.tagName = elementName;
     currentElement.attributes = attributeDict;
     currentElement.parentElement = self.currentParentElement;
     if(self.currentParentElement){
          [self.currentParentElement addChild:currentElement]; // and this one with 10%
     }

     self.currentElementValue = nil;
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
     if(!currentElement) {
          return;
     }

     if(currentElementValue == nil)
          self.currentElementValue = [NSMutableString stringWithString:string];
     else
          [currentElementValue appendString:string];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
     if(currentElement == nil){
          if( currentParentElement.parentElement){
               self.currentParentElement = currentParentElement.parentElement;
          }
     }else{
          currentElement.textValue = currentElementValue; 
          [currentElementValue release];
          currentElementValue = nil;
          self.currentParentElement = currentElement.parentElement;
          currentElement = nil;
     }
}

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

@end

【问题讨论】:

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


    【解决方案1】:

    您必须在 XMLParser 的 dealloc 方法中释放 currentElement

    它被创建为autorelease,但随后分配给retain 属性,因此您实际上只保留了一次(这很好)。

    更新:完成后你应该使用self.currentElement = nil;,而不是currentElement = nil;

    【讨论】:

      【解决方案2】:

      这个:

      self.currentElement = [[[XMLElement alloc] init] autorelease];
      

      保留currentElement(因为该属性是用retain 声明的)。

      稍后,在parser:didEndElement:namespaceURI:qualifiedName:,你这样做:

      currentElement = nil;
      

      导致泄漏是因为您没有释放currentElement

      【讨论】:

      • 感谢您的回答。我已经按照你的建议更新了它,但我仍然得到内存泄漏。这是更新的代码:
      • - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURIqualifiedName:(NSString *)qName{ //NSLog(@"处理 didEndElement: %@", 元素名); if(currentElement == nil){ if(currentParentElement.parentElement){ self.currentParentElement = currentParentElement.parentElement; } }else{ currentElement.textValue = currentElementValue; [当前元素值发布]; self.currentElementValue = nil; self.currentParentElement = currentElement.parentElement; self.currentElement = nil; } }
      • @user480451:你真的希望任何人都能阅读吗?编辑问题以将代码放入其中。
      • :) 是的,你是绝对正确的。我在这里没有找到“回复”按钮...所以我将其添加为答案
      【解决方案3】:

      从我在page 上看到的内容来看,这是一个记录在案的苹果错误。我在一些应用中遇到了同样的问题...

      【讨论】:

        【解决方案4】:

        您的XMLParser 是否在后台线程上运行?如果是这样,您需要为该线程创建一个NSAutoReleasePool,以便您的[[[XMLElement alloc] init] autorelease] 调用正常工作。

        【讨论】:

          【解决方案5】:

          大家好。 原因很简单,

          而不是

          @property(nonatomic, retain) XMLElement *parentElement;
          

          必须

          @property(nonatomic, assign) XMLElement *parentElement;
          

          您还需要从dealloc 中删除[parentElement release]

          原因是您正在创建循环引用。父母对孩子,孩子对父母

          当你重新解析解析器对象时,元素仍然出现在内存中,指针 xount > 0

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-16
            • 2012-06-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-25
            • 1970-01-01
            相关资源
            最近更新 更多