內存泄漏一直是個很頭疼的問題。這類bug的root cause通常都很難找,特別是當代碼行數達到數十萬行以上的時候。最近幫同事解決了一個此類內存泄漏的問題,原因是使用Xerces XML庫不當所引起的。
程序在長時間運行時內存不停的在漲。反覆測試後,發現只有在調用add/remove操作時內存會增長。然後進一步定位。把除了add/remove函數之外的能刪的都刪掉。但內存還是在長。調試的具體過程就不細說了,最後還是靠一個小case和google解決了問題。
精簡後的僞代碼:
- xercesc::DOMElement* createDOM(MemBufInputSource source)
- {
- XercesDOMParser parser;
- xercesc::DOMElement* doc ;
- …
- parser.parse(source);
- doc = parser.adoptDocument();
- …
- return doc;
- }
- void init()
- {
- DOMElement* _workingXercesConfig = createDOM(src1);
- }
- void add()
- {
- DOMElement* xercesConfig = createDOM(src2);
- DOMElement* xercesDuplicate = dynamic_cast<DOMElement*>(_workingXercesConfig->cloneNode(true));
- DOMNode *node = xercesDuplicate->getOwnerDocument()->importNode(xercesConfig, true);
- xercesConfig->getOwnerDocument()->release();
- _workingXercesConfig->release();
- _workingXercesConfig = xercesDuplicate;
- …
- }
看似一切都已經被釋放了,但問題的原因出在importNode()上。importNode在把新的Element導入進來的同時,會把相應的metadata及數據都導入,並掛在這顆DOM樹上。僅僅調用_workingXercesConfig->release();不會把這部分數據刪除。也就是說要釋放這塊內存,必須要把整棵DOM樹釋放並重建。
- _workingXercesConfig->getOwnerDocument()->release();
- …
- DOMElement* _configXerces = createDOM(src1);
看似簡單,卻花了我近半個月的時間才找到原因。