【问题标题】:Xerces-C++ memoryXerces-C++ 内存
【发布时间】:2018-09-15 13:33:23
【问题描述】:

我无法理解 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>

还有这段代码:

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

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

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

  • xerces-c-3.2.1,静态库,x64
  • xerces-c-3.2.1,动态 (dll),x64
  • xerces-c-3.1.2,静态库,x64

【问题讨论】:

    标签: c++ xerces-c


    【解决方案1】:

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

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

    每this (non)-bug report

    除此之外,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"
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 2011-03-15
      • 2011-05-31
      • 1970-01-01
      相关资源
      最近更新 更多