【问题标题】:Strange iPhone memory leak in xml parserxml解析器中奇怪的iPhone内存泄漏
【发布时间】:2010-11-04 12:26:54
【问题描述】:

更新:我编辑了代码,但问题依旧……

大家好,
这是我在这里的第一篇文章 - 我发现这个地方是解决我许多问题的绝佳资源。通常我会尽力自己解决任何问题,但这次我真的不知道出了什么问题,所以我希望有人能帮助我。
我正在构建一个使用 TouchXML 解析几个 xml 文件的 iPhone 应用程序。我有一个类 XMLParser,它负责下载和解析结果。当我使用同一个 XMLParser 实例多次解析 xml 文件时,出现内存泄漏。 这是解析 sn-ps 之一(只是相关部分):

for(int counter = 0; counter < [item childCount]; counter++) {  
        CXMLNode *child = [item childAtIndex:counter];
        if([[child name] isEqualToString:@"PRODUCT"]) 
        {
            NSMutableDictionary *product = [[NSMutableDictionary alloc] init];
            for(int j = 0; j < [child childCount]; j++) {
                CXMLNode *grandchild = [child childAtIndex:j];
                if([[grandchild stringValue] length] > 1) {
                    NSString *trimmedString = [[grandchild stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                    [product setObject:trimmedString forKey:[grandchild name]];
                }
            }

            // Add product to current category array
            switch (categoryId) {
                case 0:
                    [self.mobil addObject: product];
                    break;
                case 1:
                    [self.allgemein addObject: product];
                    break;
                case 2:
                    [self.besitzeIch addObject: product];
                    break;
                case 3:
                    [self.willIch addObject: product];
                    break;
                default:
                    break;
            }
            [product release];
        }

    }  

我第一次解析 xml 时没有在仪器中显示泄漏,下次我这样做时,我得到了很多泄漏(NSCFString / NSCFDictionary)。
当我深入研究一个泄露的对象时,Instruments 将我指向 CXMLNode.m 中的这个部分

theStringValue = [NSString stringWithUTF8String:(const char *)theXMLString];
if ( _node->type != CXMLTextKind )
   xmlFree(theXMLString);
}

return(theStringValue);  

我确实花了很长时间并尝试了多种方法来解决这个问题,但到目前为止都无济于事,也许我错过了一些重要的东西?

非常感谢任何帮助,谢谢!

【问题讨论】:

    标签: iphone objective-c xml memory-leaks touchxml


    【解决方案1】:

    我自己解决了这个问题。这有点愚蠢,但也许有人可能会遇到同样的事情,所以我要把它贴在这里。

    1) 我将可变数组设置为这样的实例变量:

    @interface XMLParser : NSObject {
    
    // ...  
    NSMutableArray *mobil;  
    // ...  
    }   
    @property(nonatomic, retain) NSMutableArray *mobil;  
    @end  
    

    每次我想恢复里面的新数据时,我都会这样做:
    self.mobil = nil;
    这不是我想做的,所以这是更好的方法:
    [self.mobil removeAllObjects];

    2) dealloc 方法必须像这样才能修复泄漏(因为 mobil 被定义为属性):
    -(void)dealloc {
    [美孚发布];
    self.mobil = nil;
    }

    哇,这需要做很多工作才能找到 - 希望它可以节省其他人一些时间:-)

    【讨论】:

      【解决方案2】:

      简单来说,每次你使用copy,你也必须在某个地方使用release/autorelease

      在这种情况下,更简单的答案是首先不要使用 copy,因为在复制 product 的原始版本之后,您不会对其进行任何操作。

      【讨论】:

        【解决方案3】:

        问题可能出在这一行:

        [self.mobil addObject:[product copy]];
        

        通过调用product 的副本,您正在创建一个保留计数为1 的新NSMutableDictionary 实例。但是,mobil 实例将在您向其发送addObject: 消息时增加副本的保留计数,所以现在副本的retain count是2。一般来说,一个对象负责处理自己的对象内存,所以任何时候你发消息setFoo:或者addObject:,你都可以直接传对象,即使它的autoreleased 或您计划在通话后立即释放它;如果需要保留您传递的对象,则接收者有责任保留它。

        因为您没有将副本分配给任何变量,所以您没有指针可用于减少副本的保留计数,因为您不再对它感兴趣,因此即使 mobil 发布产品在某些时候复制,副本永远不会达到 0 的保留计数。您在 for 循环末尾的 [product release] 语句会释放原始的 product 对象,而不是您创建的副本。

        相反,请尝试以下方法,看看仪器是否更快乐:

        [self.mobil addObject:product];
        

        【讨论】:

        • 非常感谢 - 我太傻了。不幸的是,泄漏仍然存在,但现在在这一行的 CXMLNode.m 类中:theStringValue = [NSString stringWithUTF8String:(const char *)theXMLString]; if ( _node->type != CXMLTextKind ) xmlFree(theXMLString); } return(theStringValue);
        • 嗯...这看起来更像是对可能泄漏的警告,而不是保证韭菜。也就是说,我在 TouchXML 中浏览了 CXMLNode 的源代码,但我根本找不到那一行……你有哪个版本的项目,它在哪一行?我从 TouchCode google 用户组中注意到,作者 Jonathan Wight 在回复帖子方面非常出色:内存泄漏:groups.google.com/group/touchcode-dev
        • 我在自己的代码中发现了漏洞,所以CXMLNode内部没有问题,只是出现了Instruments堆栈中的一个条目,但不是泄漏点...跨度>
        猜你喜欢
        • 2012-07-06
        • 2010-12-18
        • 2011-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-08
        • 2011-10-18
        相关资源
        最近更新 更多