Xerces-C++内存

Bla*_*lle 5 c++ xerces-c

我无法理解Xerces-C++内存管理.

如果我有这个(示例)XML文件"config.xml":

<?xml version="1.0" encoding="UTF-8"?>
<settings>
    <port>
        <reference>Ref1</reference>
        <label>1PPS A</label>
        <enabled>true</enabled>
    </port>
</settings>
Run Code Online (Sandbox Code Playgroud)

而这段代码:

#include <xercesc/dom/DOM.hpp>

XERCES_CPP_NAMESPACE_USE

DOMElement *nextChildElement(const DOMElement *parent)
{
    DOMNode *node = (DOMNode *)parent->getFirstChild();
    while (node)
    {
        if (node->getNodeType() == DOMNode::ELEMENT_NODE)
            return (DOMElement *)node;
        node = node->getNextSibling();
    }
    return nullptr;
}

int main(int argc, char **argv)
{
    XMLPlatformUtils::Initialize();

    XMLCh tempStr[100];
    XMLString::transcode("LS", tempStr, 99);
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    DOMLSParser *parser = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
    DOMDocument *doc = impl->createDocument(0, 0, 0);

    doc = parser->parseURI("config.xml");

    DOMElement *el = doc->getDocumentElement(); // <settings>
    el = nextChildElement(el);                  //   <port>
    el = nextChildElement(el);                  //     <reference>Ref1</reference>

    // Heap blows up here
    while (1) {
        char *cstr = XMLString::transcode(el->getTextContent());
        XMLString::release(&cstr); // cstr is "Ref1"
    }

    // and/or here
    while (1) {
        XMLCh *xstr = XMLString::replicate(el->getTextContent());
        char *cstr = XMLString::transcode(xstr); // cstr is "Ref1"
        XMLString::release(&cstr);
        XMLString::release(&xstr);
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么程序(堆)内存在while (1)循环中爆炸.两个循环都会导致相同的内存问题:

xerces内存诊断

注意:我正在使用Visual Studio 2017,并且我已经在这些配置中对其进行了测试(所有结果都相同):

  • xerces-c-3.2.1,static lib,x64
  • xerces-c-3.2.1,dynamic(dll),x64
  • xerces-c-3.1.2,static lib,x64

Bla*_*lle 4

问题是函数const XMLCh *getTextConent()在 Document 堆上分配内存(使用其 MemoryManager),并且没有规定允许调用者释放内存或将其标记为回收。因此,一旦返回的指针从调用者的堆栈中删除,内存基本上就成为孤立的,直到整个 Document 被释放,此时 MemoryManager 会删除所有堆分配。

解决方案是不使用getTextContent(),而是使用getNodeValue(),它返回指向数据的指针,而不是从内部堆中重新分配它。

根据此(非)错误报告

除此之外, getTextContent 无论如何都不起作用。这是有缺陷的,因为所有的东西都出去了并且实际上毫无用处。您无法以这种方式读取 DOM,否则如果存在不相邻的 Text 节点,您将在各种不同的情况下得到不准确的数据(如果不存在,则无论如何都不需要使用它,因为直接节点值将是您所需要的)。

因此,OP 示例代码的工作版本可能如下所示:

#include <xercesc/dom/DOM.hpp>
#include <string>

XERCES_CPP_NAMESPACE_USE

DOMElement *nextChildElement(const DOMElement *parent)
{
    DOMNode *node = (DOMNode *)parent->getFirstChild();
    while (node)
    {
        if (node->getNodeType() == DOMNode::ELEMENT_NODE)
            return (DOMElement *)node;
        node = node->getNextSibling();
    }
    return nullptr;
}

std::string readTextNode(const DOMElement *el)
{
    std::string sstr;
    DOMNode *node = el->getFirstChild();
    if (node->getNodeType() == DOMNode::TEXT_NODE) {
        char *cstr = XMLString::transcode(node->getNodeValue());
        sstr = cstr;
        XMLString::release(&cstr);
    }
    return sstr;
}

int main(int argc, char **argv)
{
    XMLPlatformUtils::Initialize();

    XMLCh tempStr[100];
    XMLString::transcode("LS", tempStr, 99);
    DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
    DOMLSParser *parser = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
    DOMDocument *doc = impl->createDocument(0, 0, 0);

    doc = parser->parseURI("config.xml");

    DOMElement *el = doc->getDocumentElement(); // <settings>
    el = nextChildElement(el);                  //   <port>
    el = nextChildElement(el);                  //     <reference>Ref1</reference>

    // No memory leak
    std::string nodestr;
    while (1) {
        nodestr = readTextNode(el); // nodestr is "Ref1"
    }
}
Run Code Online (Sandbox Code Playgroud)