繁体   English   中英

MSXML6 XML解析中的内存泄漏

[英]Memory Leaks in MSXML6 XML Parsing

我已经编写了MFC DLL,该DLL可以加载XML文件或XML字符串并进行解析。 它使用xml元素填充一张地图。 我正在使用MSXML2 :: DOMDocument60并且可以解析整个xml。 但是,如果我在循环中迭代整个过程(200-500次),我可能会看到巨大的内存泄漏。 我评论了填充映射并仅迭代整个xml,然后只有我可以在任务管理器中看到内存泄漏。 我检查了所有用于释放的指针,但无法停止此内存泄漏。 MSXML6> LoadFile API本身是否存在内存泄漏? 您能帮上忙吗?

注意:我已经在Init方法中初始化了COM,而在Dispose方法中未初始化了它。 此代码。 下面的代码未提及这些方法。

码:

C ++ DLL:

bool CXMLSerializer::LoadFile(const char* sXmlData)
{
    bool bResult = false;
    static SAFEARRAY* psa = NULL;
    static MSXML2::IXMLDOMDocumentPtr xmlDocPtr; 

    //Create an instance of the DOMDocument object:
    xmlDocPtr.CreateInstance(__uuidof(MSXML2::DOMDocument60));

    try
    {
        VARIANT_BOOL varResult((bool)FALSE);
        if(sXmlData == NULL)
        {
            _tprintf(_T("XML Data received is Null, Loading XML document from XMLFile\n"));
            if(FileExists(m_sXmlFileName))
            {
                _tprintf(_T("Loading XML: %s\n"), m_sXmlFileName);
                //Load a document:
                _variant_t varXml(m_sXmlFileName);  //XML file to load
                varResult = xmlDocPtr->load(varXml);
            }
            else
            {
                _tprintf(_T("Failed to open XML file %s\n"), m_sXmlFileName);
            }
        }
        else
        {
            _tprintf(_T("XML string received, Loading data...\n"));
            SAFEARRAYBOUND rgsabound[1];
            rgsabound[0].lLbound = 0;
            rgsabound[0].cElements = strlen(sXmlData);

            psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
            if(psa != NULL)
            {
                memcpy(psa->pvData, sXmlData, strlen(sXmlData));
                VARIANT v;
                VariantInit(&v);
                V_VT(&v) = VT_ARRAY | VT_UI1;
                V_ARRAY(&v) = psa;
                varResult = xmlDocPtr->load(v);
                VariantClear(&v);
            }
            else
            {
                _tprintf(_T("Error: SafeArrayCreate failed\n"));
            }
        }

        if(varResult == VARIANT_TRUE)
        {
            _tprintf(_T("XML document loaded successfully\n"));
            if (DeserializeRules(xmlDocPtr))
            {
                _tprintf(_T("XML Deserialized successfully\n"));
                bResult = true;
            }
            else
            {
                _tprintf(_T("XML Deserialization failed\n"));
            }
        }
        else
        {
            _tprintf(_T("XML document load failed\n"));
        }
    }
    catch(...)
    {
        _tprintf(_T("ERROR: Exception occured in LoadFile()\n"));
    }

    //GetXML
    m_sXmlData = SerializeRules(xmlDocPtr);

    if(psa)
    {
        SafeArrayDestroy(psa);
        psa = NULL;
    }
    if(xmlDocPtr)
    {
        xmlDocPtr.Release();
    }
    ::CoFreeUnusedLibraries();
    return bResult;
}

bool CXMLSerializer::DeserializeRules(MSXML2::IXMLDOMDocumentPtr xmlDocPtr)
{
    bool bParseResult = false;
    static MSXML2::IXMLDOMNodeListPtr NodeListPtr;              //indexed access. and iteration through the collection of nodes
    static MSXML2::IXMLDOMNode *pIDOMNode = NULL;               //pointer to element's node
    static MSXML2::IXMLDOMNodeList *pChildList=NULL;            //node list containing the child nodes

    try 
    {
        //clear data structures
        m_pRules->m_mapTitleParserApp.clear();

        //Variable with the name of node to find: 
        BSTR strFindText = L"*";    //" " means to output every node

        //Variables to store item's name, parent, text and node type:
        BSTR bstrItemText, bstrItemNode, bstrNodeType;

        int i = 0;  //loop-index variable
        bool bResult = false;
        CString sApplicationName = L"";
        HRESULT hr;

        //Collect all or selected nodes by tag name:
        NodeListPtr = xmlDocPtr->getElementsByTagName(strFindText);

        //root node:
        xmlDocPtr->documentElement->get_nodeName(&bstrItemText);

        for(i = 0; i < (NodeListPtr->length); i++)
        {
            if(pIDOMNode) pIDOMNode->Release();
            NodeListPtr->get_item(i, &pIDOMNode);
            if(pIDOMNode)
            {               
                pIDOMNode->get_nodeTypeString(&bstrNodeType);

                //process only elements (nodes of "element" type): 
                BSTR temp = L"element";
                int ft;
                CString cs;

                //........Commented assigning elements to map.......//
                //.......Even I could see Leaks at TaskManager....//

            }
        }
        if(NodeListPtr) 
            NodeListPtr.Release();

        if(pChildList)
            pChildList->Release();

        bParseResult = true;        
        m_bIsXMLParsed = true;
        _tprintf(_T("Deserialize - Size of mapTitleParserApp: %d\n"), m_pRules->m_mapTitleParserApp.size());
    }
    catch(...)
    {
        _tprintf(_T("ERROR: Exception occured in Deserialize()\n"));
    }
    return bParseResult;
}

CString CXMLSerializer::SerializeRules()
{
    CString sXmlData = L"";
    sXmlData = (LPCTSTR) m_xmlDocPtr->Getxml();
    return sXmlData;
}

C#测试应用程序:

strDataDir = @"C:\temp";
string sXMLData = null;
NativeDLLHelper.Init(strUserDataDir, 15);
for (i = 0; i < 500; i++)
{
    NativeDLLHelper.LoadFile(sXMLData);
    Console.WriteLine("i: " + i);
}
NativeDLLHelper.Dispose();
Console.ReadLine();

您需要在for循环结束时释放pIDOMNode()

不太确定为什么有些变量需要为static变量,它们占用的空间不多(据我所知,它们只是指针)...

我可以通过释放BSTR分配的内存来解决此问题。 由于BSTR是原始指针,因此我们需要使用SysFreeString MSDN释放内存。 添加SysFreeString之后,我可以看到稳定的内存。 同样,我们可以将BSTR替换为_bstr_t,其工作方式类似于智能指针。 当变量超出范围时,它将释放内存。 感谢你的帮助!!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM