【问题标题】:libxml2.2.dylib creating lot of memory leaklibxml2.2.dylib 造成大量内存泄漏
【发布时间】:2012-03-29 00:58:33
【问题描述】:

在我的项目中实现 using XpathQuery 时,我很难消除/避免泄漏。目前我正在使用 libXml2.2.dylib 进行解析。当我使用工具检查内存泄漏时,我发现框架中有很多泄漏。

避免这些泄漏的解决方案是什么。记忆对我们来说更重要。如何修复/避免这些漏洞?

【问题讨论】:

  • @Moshe:没用,libxml2 是一个 C 库。
  • 我们可以使用任何最新版本的 libxml2
  • 不要单独依赖 Instruments - 它可能会引入误报。

标签: iphone objective-c ios xml-parsing libxml2


【解决方案1】:

如果您使用的是 TFHpple,那么您需要在

中添加以下代码

DictionaryForNode

方法

XPathQuery 类

if (XML_ELEMENT_NODE != currentNode->type) {
    return nil;
}

所以你的最终方法应该看起来像

NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult,BOOL parentContent)
{
NSMutableDictionary *resultForNode = [NSMutableDictionary dictionary];
if (currentNode->name) {
    NSString *currentNodeContent = [NSString stringWithCString:(const char *)currentNode->name
                                                      encoding:NSUTF8StringEncoding];
    resultForNode[@"nodeName"] = currentNodeContent;
}

if (XML_ELEMENT_NODE != currentNode->type) {
    return nil;
}

xmlChar *nodeContent = xmlNodeGetContent(currentNode);

if (nodeContent != NULL) {
    NSString *currentNodeContent = [NSString stringWithCString:(const char *)nodeContent
                                                      encoding:NSUTF8StringEncoding];
    if ([resultForNode[@"nodeName"] isEqual:@"text"] && parentResult) {
        if (parentContent) {
            NSCharacterSet *charactersToTrim = [NSCharacterSet whitespaceAndNewlineCharacterSet];
            parentResult[@"nodeContent"] = [currentNodeContent stringByTrimmingCharactersInSet:charactersToTrim];
            xmlFree(nodeContent);
            return nil;
        }
        if (currentNodeContent != nil) {
            resultForNode[@"nodeContent"] = currentNodeContent;
        }
        return resultForNode;
    } else {
        resultForNode[@"nodeContent"] = currentNodeContent;
    }
    xmlFree(nodeContent);
}

xmlAttr *attribute = currentNode->properties;
if (attribute) {
    NSMutableArray *attributeArray = [NSMutableArray array];
    while (attribute) {
        NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
        NSString *attributeName = [NSString stringWithCString:(const char *)attribute->name
                                                   encoding:NSUTF8StringEncoding];
        if (attributeName) {
            attributeDictionary[@"attributeName"] = attributeName;
        }

        if (attribute->children) {
            NSDictionary *childDictionary = DictionaryForNode(attribute->children, attributeDictionary, true);
            if (childDictionary) {
                attributeDictionary[@"attributeContent"] = childDictionary;
            }
        }

        if ([attributeDictionary count] > 0) {
            [attributeArray addObject:attributeDictionary];
        }
        attribute = attribute->next;
    }

    if ([attributeArray count] > 0) {
        resultForNode[@"nodeAttributeArray"] = attributeArray;
    }
}

xmlNodePtr childNode = currentNode->children;
if (childNode) {
    NSMutableArray *childContentArray = [NSMutableArray array];
    while (childNode) {
        NSDictionary *childDictionary = DictionaryForNode(childNode, resultForNode,false);
        if (childDictionary) {
            [childContentArray addObject:childDictionary];
        }
        childNode = childNode->next;
    }
    if ([childContentArray count] > 0) {
        resultForNode[@"nodeChildArray"] = childContentArray;
    }
}

xmlBufferPtr buffer = xmlBufferCreate();
xmlNodeDump(buffer, currentNode->doc, currentNode, 0, 0);
NSString *rawContent = [NSString stringWithCString:(const char *)buffer->content encoding:NSUTF8StringEncoding];
if (rawContent != nil) {
    resultForNode[@"raw"] = rawContent;
}
xmlBufferFree(buffer);
return resultForNode;
}

【讨论】:

    【解决方案2】:

    我解决了这个问题。当我的文档中有空标签时我得到了泄漏,我清楚地观察并修改了一些代码。基本上我在我的 XpathQuery.m 中纠正了。

    NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query)
    {
        xmlXPathContextPtr xpathCtx; 
        xmlXPathObjectPtr xpathObj;
        /* Create xpath evaluation context */
        xpathCtx = xmlXPathNewContext(doc);
        if(xpathCtx == NULL)
        {
            return nil;
        }
        /* Evaluate xpath expression */
        xpathObj = xmlXPathEvalExpression((xmlChar *)[query cStringUsingEncoding:NSUTF8StringEncoding], xpathCtx);
        if(xpathObj == NULL) {
            GLogInfo(@"%@",@"Unable to evaluate XPath");
            xmlXPathFreeObject(xpathObj);
            xmlXPathFreeContext(xpathCtx); 
            return nil;
        }
    
        xmlNodeSetPtr nodes = xpathObj->nodesetval;
        if (!nodes)
        {
            GLogInfo(@"%@",@"Nodes was nil.");
            xmlXPathFreeObject(xpathObj);
            xmlXPathFreeContext(xpathCtx); 
            return nil;
        }
    
        NSStringEncoding encoding = cocoaEncodingFromXmlEncodingConst(doc->encoding);
        NSMutableArray *resultNodes = [NSMutableArray array];
        for (NSInteger i = 0; i < nodes->nodeNr; i++)
        {
            NSDictionary *nodeDictionary = DictionaryForNode(nodes->nodeTab[i], nil, encoding);
            if (nodeDictionary)
            {
                [resultNodes addObject:nodeDictionary];
            }
        }
    
        /* Cleanup */
        xmlXPathFreeObject(xpathObj);
        xmlXPathFreeContext(xpathCtx); 
        return resultNodes;
    }
    

    如果您使用相同的类,您绝对可以毫无疑问地使用此方法/考虑内存泄漏。祝你好运。

    【讨论】:

    • 真正的问题在于 xmlChar *nodeContent = xmlNodeGetContent(currentNode);
    【解决方案3】:

    首先,如果内存是一个主要问题,那么使用 XML 无论如何都不是您的最佳解决方案。 JSON 或二进制格式的内存效率更高。

    其次,您的跟踪不会显示框架中的泄漏。显示的是泄漏的对象,其内存由框架分配。实际泄漏更有可能在您的代码中,通常是通过从库中分配一个对象,但随后不释放(或在这种情况下释放)该对象。查看堆栈跟踪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-21
      • 1970-01-01
      • 2013-09-02
      • 2015-03-07
      • 2013-03-11
      • 2014-05-13
      • 1970-01-01
      • 2011-03-20
      相关资源
      最近更新 更多