簡體   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