Я написал MFC DLL, которая загружает XML-файл или XML-строку и анализирует ее. Он заполняет одну карту элементами xml. Я использую MSXML2 :: DOMDocument60 и могу проанализировать весь XML. Но если я повторяю весь процесс внутри цикла (200-500 раз), я могу видеть огромные утечки памяти. Я прокомментировал заполнение карты и повторил только весь XML, тогда только я вижу утечки памяти в диспетчере задач. Я проверил все используемые указатели на выпуск, но не смог остановить эту утечку памяти. MSXML6> LoadFile API имеет утечки памяти? Не могли бы вы помочь в этом.
Примечание. Я инициализировал COM в методе Init и неинициализировал его в методе 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();
Вы должны выпустить pIDOMNode()
в конце цикла.
Не очень уверен, почему некоторые из ваших переменных должны быть static
они не занимают много места (насколько я вижу, они всего лишь указатели) …
Я мог бы решить эту проблему, освободив память, выделенную BSTR. Поскольку BSTR является необработанным указателем, нам нужно освободить память, используя SysFreeString MSDN. После добавления SysFreeString я мог видеть стабильную память. Также мы можем заменить BSTR на _bstr_t, который работает как интеллектуальный указатель. Он освобождает память, когда переменная выходит из области видимости. Спасибо за вашу помощь!!