2013-10-25 25 views
0

我使用Delphi 7 XMLDoc單元在XML基礎上構建協議定義,即協議在XML文件中定義,並且一些對象從此XML中獲取信息以分解和構建在TCP/IP上傳送的​​ISO8583消息。我廣泛使用了IXMLDocumentIXMLNode接口。一切都很好,在終止點沒有內存泄漏(使用FASTMM)。但在運行期間,軟件會慢慢消耗內存。釋放對象時以某種方式釋放內存 - 源自TXMLDocument - 我用於XML訪問。我分析並發現,如果我沒有使用IXMLDocumentIXMLNode接口,但是我當然需要的話,沒有內存問題。使用Delphi7的內存問題XMLDoc

我有一個對象(TXMLTree)從TXMLDocmument得出:

TXMLTree = class(TXMLDocument, IXMLDocument) 
... 
end; 

我有另一個對象(TDPR),並在其構造函數創建TXMLTree並獲得接口(fIDocument)加上一個接口文檔的起點點(fIDocStart),以及:

TDPR = class(TObject) 
... 
    fIDocument:IXMLDocument; 
    fIDocStart:IXMLNode; 
... 
end; 

constructor TDPR.Create(aFilename: string); 
begin 
    inherited; 
... 
    fTree := TXMLTree.Create(aFilename); 
    fTree.GetInterface(IXMLDocument, fIDocument); 

    fIDocStart := fIDocument.DocumentElement; 
... 
end; 

一般我使用fIDocumentfIDocStart爲起點到達XML文檔,寫這樣的代碼:

node := fIDocument.DocumentElement.ChildNodes[aName].ChildNodes.FindNode(aFieldName); 

node := fIDocStart.ChildNodes[aName].ChildNodes.FindNode(aFieldName); 

只有一個這樣的行,就足以緩慢地提高內存的使用,但如果我在for循環例如執行它千萬不會有更多的影響,因爲 - 我猜 - 只有一個參考被使用並在循環中一路發佈。

現在,讓我們有一個程序Foo從哪裏獲得該文件的出發點:

procedure TDPR.Foo; 
var lNode:IXMLNode; 
begin 
    lNode := IDocument.DocumentElement; 
end; 

如果我把這個過程它增加內存使用了一點,但週期性地調用它,它是時間的運行只是時間問題內存不足。
但是:如果我使用fIDocStart已經存儲所需的接口 - 所以不需要再次調用DocumentElement - 沒有內存問題。

procedure TDPR.Foo; 
var lNode:IXMLNode; 
begin 
    lNode := fIDocStart; 
end; 

如此看來,每一個獲取並返回一個接口對象(IXMLDocumentIXMLNodeIXMLNodeList等)調用分配一些內存,並且不釋放它,而參考對象都被正確釋放。即使我們要求同一個節點。當然,我不能存儲所有可能的節點,以避免使用內存。

TDPR的析構函數中,我通過將對應接口設置爲nil來釋放TXMLTree,並且在終止時未檢測到存儲器泄漏。引用計數器似乎沒問題。

destructor TDPR.Destroy; 
begin 
... 
    fIDocStart := nil; 
    fIDocument := nil; 

... 
    inherited; 
end; 

而且它無關,與大XML文件。問題是相同的蒙山XML這樣的:

<?xml version="1.0"?> 
<?xml-stylesheet type="text/xsl"?> 
<Base24-POS> 
    <Instructions> 
     <Parameters Receive="1"/> 
    </Instructions> 
</Base24-POS> 

我知道它是模糊的,我只要求拿到有人已經碰到了同樣的問題,可以找到解決方案的機會。 (順便提一句,我記得在WindowsXP中使用的代碼相同,沒有問題,現在是Windows7)

+5

請提供SSCCE –

+0

並檢查您是否沒有存儲接口參考。 – Runner

+0

如果我可能通過不允許釋放對象來存儲會導致內存泄漏的接口引用。但爲什麼它會將內存使用量增加到最終?在程序結束時,沒有檢測到內存泄漏。 – peter

回答

0

我發現問題與多線程訪問COM對象有關(XMLDocument是COM)。在單線程上創建TXMLDocument並通過接口(如IXMLDocumentIXMLNode)對其進行操作時,沒有內存「泄漏」。但使用不同的線程我無法消除這個問題。我用參數COINIT_MULTITHREADED使用CoInitializeEx。看起來,每個線程在獲取接口時都會分配一些內存,並且不釋放它,並且每個線程都會分配一次 - 至少對於某個接口來說,所以一個線程不會導致可見的內存泄漏。但動態創建的線程都無法釋放該內存,並最終消耗進程內存。到目前爲止,我還沒有找到解決方案,因此我認爲使用SetProcessWorkingSet(ProcessHandle, -1, -1)定期清潔記憶,症狀治療解決了問題,直到達到更好的解決方案。我也開啓了一個專門討論這個問題的新問題Memory consumption when using Delphi7 COM interfaces in a multithreaded way