Libxml2.2.dylib creates many memory leaks
I am really having a hard time fixing / avoiding leaks when implementing the use of XpathQuery in my project. I am currently using libXml2.2.dylib for parsing. When I was checking for memory leaks with tools, I found many leaks in the framework.
What would be the solution to avoid these leaks. Memory bothers us more. How can I fix / avoid these errors?
source to share
First, if memory is a serious issue, using XML is not your best solution. JSON or binary format is much more efficient.
Secondly, your footprint does not show leaks within the framework. What is showing are leaked objects whose memory has been allocated by the framework. Most likely an actual leak in your code, usually by allocating an object from the library, but then not freeing (or freeing in this case) the object. Take a look at the stack traces.
source to share
I solved the problem. I got leaks when I have empty tags in my documents that I have clearly observed and modified some code. This fix me in my 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;
}
If you are using the same class, you can use this method absolutely without any hesitation / thought of a memory leak. Good luck.
source to share
if you are using TFHpple then you need to add the following code to
DictionaryForNode
method
XPathQuery class
if (XML_ELEMENT_NODE != currentNode->type) {
return nil;
}
So your final method should look like
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;
}
source to share