xml 解析器中奇怪的 iPhone 内存泄漏

发布于 2024-07-25 05:52:19 字数 2093 浏览 4 评论 0原文

更新:我编辑了代码,但问题仍然存在...

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

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);  

我确实花了很长时间并尝试了多种方法来修复此问题,但到目前为止没有任何效果,也许我是缺少一些重要的东西吗?

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

Update: I edited the code, but the problem persists...

Hi everyone,
this is my first post here - I found this place a great ressource for solving many of my questions. Normally I try my best to fix anything on my own but this time I really have no idea what goes wrong, so I hope someone can help me out.
I am building an iPhone app that parses a couple of xml files using TouchXML. I have a class XMLParser, which takes care of downloading and parsing the results. I am getting memory leaks when I parse an xml file more than once with the same instance of XMLParser.
Here is one of the parsing snippets (just the relevant part):

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];
        }

    }  

The first time, I parse the xml no leak shows up in instruments, the next time I do so, I got a lot of leaks (NSCFString / NSCFDictionary).
Instruments points me to this part inside CXMLNode.m, when I dig into a leaked object:

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

return(theStringValue);  

I really spent a long time and tried multiple approaches to fix this, but to no avail so far, maybe I am missing something essential?

Any help is highly appreciated, thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千纸鹤 2024-08-01 05:52:19

问题可能出在这一行:

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

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

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

相反,请尝试以下操作,看看 Instruments 是否更满意:

[self.mobil addObject:product];

The issue is likely in this line:

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

By calling for a copy of product you're creating a new NSMutableDictionary instance with a retain count of 1. The mobil instance, however, will increment the copy's retain count when you send it the addObject: message, so the retain count of the copy is now 2. Generally speaking, an object is responsible for handling its own object memory, so any time you message setFoo: or addObject:, you can just pass the object directly, even if its autoreleased or you are planning to release it right after the call; it is the receiver's responsibility to retain the object you're passing if it needs to hold onto it.

Because you did not assign the copy to any variable, you do not have a pointer that you can use to decrement the copy's retain count now that you're no longer interested in it, so even if mobil releases the product copy at some point, the copy will never reach a retain count of 0. Your [product release] statement at the end of the for loop releases the original product object, not the copy you created.

Instead, try the following and see if instruments is happier:

[self.mobil addObject:product];
欲拥i 2024-08-01 05:52:19

简单来说,每次使用copy时,你还必须在某处使用release/autorelease

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

In simple terms, every time you use copy, you also have to use release/autorelease somewhere.

And in this instance, the even easier answer is to not use copy in the first place, since you aren't doing anything with the original version of product after you've copied it.

长不大的小祸害 2024-08-01 05:52:19

我自己解决了这个问题。 这有点愚蠢,但也许有人可能遇到同样的事情,所以我将其发布在这里。

1)我将可变数组设置为实例变量,如下所示:

@interface XMLParser : NSObject {

// ...  
NSMutableArray *mobil;  
// ...  
}   
@property(nonatomic, retain) NSMutableArray *mobil;  
@end  

每次我想恢复其中的新数据时,我都会这样做:
self.mobil = nil;
这不是我想做的,所以这是更好的方法:
[self.mobil 删除所有对象];

2) dealloc 方法必须像这样来修复泄漏(因为 mobil 被定义为属性):
-(void)dealloc {
[移动版本];
self.mobil = nil;

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

I fixed the problem myself. It was kind of stupid, but maybe someone might come across the same thing, so I am going to post it here.

1) I had mutable array set up as instance variables like this:

@interface XMLParser : NSObject {

// ...  
NSMutableArray *mobil;  
// ...  
}   
@property(nonatomic, retain) NSMutableArray *mobil;  
@end  

Everytime I wanted to restore new data inside I did:
self.mobil = nil;
Which did not what I wanted to do, so this is the better approach:
[self.mobil removeAllObjects];

2) The dealloc method has to be like this to fix the leaks (because mobil is defined as a property):
-(void)dealloc {
[mobil release];
self.mobil = nil;
}

Whew, that has been a lot of work to find out - hope it saves someone else some time :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文